from typing import (
    Any,
    Dict,
    List,
    Optional,
)
from xml.etree import cElementTree as eTree

from common import FiscalOrderTotals
from common.builder_functions import optional
from nreports.utils import get_logo_image_str
from nreports_api.shared import JSON
from ._BaseFiscalNfce import BaseFiscalNfce


class FiscalCouponNfceBuilder(BaseFiscalNfce):

    def build_data(
        self,
        data_to_build: Dict[str, JSON],
        **kwargs: Any,
    ) -> Dict[str, JSON]:

        fiscal_xml = kwargs["fiscalXml"]
        logo_image = get_logo_image_str(image_path=self.images_path["STORE_IMG_LOGO"])

        fiscal_order_totals = FiscalOrderTotals(fiscal_xml=fiscal_xml)

        self._build_header(
            data_to_build=data_to_build,
            fiscal_xml=fiscal_xml,
            logo_image=logo_image,
        )

        self._build_body(
            data_to_build=data_to_build,
            fiscal_xml=fiscal_xml,
            fiscal_order_totals=fiscal_order_totals,
            products=self._get_item_products(fiscal_xml=fiscal_xml),
        )

        self._build_footer(
            data_to_build=data_to_build,
            fiscal_xml=fiscal_xml,
        )

        data_to_build["CUSTOMER_IDENTIFICATION"] = self._get_customer_identification(fiscal_xml=fiscal_xml)
        data_to_build["CUSTOMER_NOT_IDENTIFIED"] = not data_to_build["CUSTOMER_IDENTIFICATION"]

        return data_to_build

    def _get_customer_identification(
        self,
        fiscal_xml: eTree.Element,
    ) -> Optional[str]:

        customer_name = optional(element=fiscal_xml.find(".//dest/xNome")) or "NÃO IDENTIFICADO"
        customer_doc = self._get_customer_doc(fiscal_xml=fiscal_xml)
        customer_address = self._get_customer_address(fiscal_xml=fiscal_xml)

        return " - ".join(filter(None, [customer_name, customer_doc, customer_address])) or None

    @staticmethod
    def _get_customer_doc(
        fiscal_xml: eTree.Element,
    ) -> Optional[str]:

        cpf = optional(element=fiscal_xml.find(".//dest/CPF"))
        if cpf:
            return f"CPF {cpf}"

        cnpj = optional(element=fiscal_xml.find(".//dest/CNPJ"))
        if cnpj:
            return f"CNPJ {cnpj}"

        return None

    @staticmethod
    def _get_customer_address(
        fiscal_xml: eTree.Element,
    ) -> Optional[str]:

        address = optional(element=fiscal_xml.find(".//enderDest/xLgr"))
        number = optional(element=fiscal_xml.find(".//enderDest/nro"))
        complement = optional(element=fiscal_xml.find(".//enderDest/xCpl"))
        neighborhood = optional(element=fiscal_xml.find(".//enderDest/xBairro"))
        city = optional(element=fiscal_xml.find(".//enderDest/xMun"))
        uf = optional(element=fiscal_xml.find(".//enderDest/UF"))
        cep = optional(element=fiscal_xml.find(".//enderDest/CEP"))

        return " - ".join(filter(None, [address, number, complement, neighborhood, city, uf, cep])) or None

    @staticmethod
    def _get_item_products(
        fiscal_xml: eTree.Element,
    ) -> List[Dict[str, str]]:

        item_products: List[Dict[str, str]] = []
        fiscal_products = fiscal_xml.findall(".//prod")
        for product in fiscal_products:
            item_products.append(
                {
                    "ITEM_PRODUCT_CODE": product.find("cProd").text,
                    "ITEM_PRODUCT_NAME": product.find("xProd").text,
                    "ITEM_PRODUCT_QUANTITY": f"{float(product.find('qCom').text):.3f}",
                    "ITEM_PRODUCT_UNIT": product.find("uCom").text.upper(),
                    "ITEM_PRODUCT_PRICE": f"{float(product.find('vUnCom').text):.2f}",
                    "ITEM_PRODUCT_TOTAL_PRICE": f"{float(product.find('vProd').text):.2f}",
                }
            )

        return item_products
