from logging import Logger
from xml.etree import ElementTree as eTree

from cfgtools import Configuration
from helper import remove_accents
from pos_model import (
    Fee,
    Order,
    SaleItem,
)
from typing import (
    List,
    Optional,
)

from common import (
    CalculateTaxesItemCommon,
    FiscalParameterController,
    build_item_taxes,
)
from models import FeeDetails

_FEE_DETAILS_CACHE = []    # type: List[FeeDetails]


def get_order_fees(
    order_xml,  # type: eTree.Element
):
    # type: (...) -> List[Fee]

    order_fees = []
    for order_fee in order_xml.findall(".//OrderFees/Fee"):
        fee = Fee(
            code=order_fee.get("code"),
            amount=float(order_fee.get("calculatedAmount")),
        )
        order_fees.append(fee)

    return order_fees


def get_fee_details(
    fee_code,   # type: str
):
    # type: (...) -> Optional[FeeDetails]

    for fee in _FEE_DETAILS_CACHE:
        if fee.code == fee_code:
            return fee

    return None


class FeeService(object):

    def __init__(
        self,                           # type: FeeService
        loader_config,                  # type: Configuration
        logger,                         # type: Logger
        calculate_taxes_common,         # type: CalculateTaxesItemCommon
        fiscal_parameter_controller,    # type: FiscalParameterController
    ):
        # type: (...) -> None

        self.loader_config = loader_config
        self.logger = logger
        self.calculate_taxes_common = calculate_taxes_common
        self.fiscal_parameter_controller = fiscal_parameter_controller

        self._read_fees_details()

    def get_fee_sale_items(
        self,   # type: FeeService
        order,  # type: Order
    ):
        # type: (...) -> List[SaleItem]

        fee_sale_items = []

        for fee in order.fees:
            fee_item = self._build_fee_item(fee=fee)
            if fee_item:
                fee_sale_items.append(fee_item)

        return fee_sale_items

    def _build_fee_item(
        self,   # type: FeeService
        fee,    # type: Fee
    ):
        # type: (...) -> Optional[SaleItem]

        fee_details = get_fee_details(fee_code=fee.code)
        if not fee_details:
            return None

        sale_item = SaleItem()
        sale_item.part_code = fee_details.product_code
        sale_item.product_name = fee_details.product_name.upper()
        sale_item.quantity = 1
        sale_item.unit_price = sale_item.item_price = fee.amount
        sale_item.taxes = build_item_taxes(
            sale_item=sale_item,
            fiscal_parameter_controller=self.fiscal_parameter_controller,
            calculate_taxes_common=self.calculate_taxes_common,
        )

        return sale_item

    def _read_fees_details(
        self,   # type: FeeService
    ):
        # type: (...) -> None

        global _FEE_DETAILS_CACHE

        main_group = self.loader_config.find_group(path="FiscalWrapper.FeesFiscalParameters")
        if not main_group:
            return

        for group in main_group.groups:

            fee_details = FeeDetails(code=str(group.name))

            for key in group.keys:
                key_name = str(key.name)
                if key_name == "PRODUCT_CODE":
                    fee_details.product_code = str(key.values[0])
                elif key_name == "PRODUCT_NAME":
                    fee_details.product_name = str(remove_accents(key.values[0]))

            _FEE_DETAILS_CACHE.append(fee_details)


def order_xml_has_valid_fee(
    order_xml,  # type: eTree.Element
):
    # type: (...) -> bool

    order_fees = get_order_fees(order_xml=order_xml)
    if not order_fees:
        return False

    for order_fee in order_fees:
        if not get_fee_details(fee_code=order_fee.code):
            return False

    return True
