import json

from common import FiscalParameterController, CalculateTaxesItemCommon
from typing import Dict, List

from msgbus import MBEasyContext
from pos_model import Order, SaleItem


class TipBuilderCommon(object):
    def __init__(self, tip_config, tip_config_range, mb_context, fiscal_parameter_controller, calculate_taxes_common):
        # type: (Dict, Dict, MBEasyContext, FiscalParameterController, CalculateTaxesItemCommon) -> None

        self.mb_context = mb_context
        self.tip_config = tip_config
        self.tip_config_range = tip_config_range
        self.fiscal_parameter_controller = fiscal_parameter_controller
        self.calculate_taxes_common = calculate_taxes_common

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

        if order.tip:
            if len(self.tip_config_range) > 0:
                return self._build_tip_by_range(order)

            if len(self.tip_config) > 0 and self.tip_config['TipCode'] and self.tip_config['TipName']:
                price = order.tip
                return [self._get_sale_line_tip(self.tip_config['TipCode'], self.tip_config['TipName'].upper(), price)]

        return []

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

        items = []
        tip_ranges = self.get_percentage_by_tip(order.total_gross, order.tip)

        for key, value in tip_ranges.items():
            items.append(self._get_sale_line_tip(key, value.get("TipName"), value.get("TipValue")))

        return items

    def get_percentage_by_tip(self, total_gross, tip):
        # type: (float, float) -> Dict

        result = {}
        remaining_tip = tip
        for item in self.tip_config_range:
            code = item.get("TipCode")
            percentage = abs(item.get("PercentageUpper"))
            value = (percentage * total_gross) / 100.0
            current_tip = value if value <= remaining_tip else remaining_tip
            result[code] = {"TipName": item.get("TipName"), "TipValue": current_tip}
            remaining_tip -= current_tip

            if remaining_tip <= 0:
                break

        return result

    @staticmethod
    def value_tip_by_percentage(percent, order_value):
        # type: (float, float) -> float

        return (percent * order_value) / 100.0

    def _get_sale_line_tip(self, part_code, product_name, price):
        # type: (str, str, float) -> SaleItem

        sale_item = SaleItem()
        sale_item.part_code = str(part_code)
        sale_item.product_name = str(product_name.upper())
        sale_item.quantity = 1
        sale_item.unit_price = price
        sale_item.item_price = price
        taxes_calc = self.fiscal_parameter_controller.get_tip_params(part_code)
        cst_icms = self.fiscal_parameter_controller.get_tip_params(part_code, ['CST_ICMS'])
        cst_icms = None if len(cst_icms) == 0 else {part_code: cst_icms[0]['rate']}
        base_reduction = self.fiscal_parameter_controller.get_tip_params(part_code, ['BASE_REDUCTION'])
        base_reduction = None if len(base_reduction) == 0 else {part_code: base_reduction[0]['rate']}
        taxes = json.dumps(taxes_calc).encode("utf-8")
        sale_item.taxes = self.calculate_taxes_common.get_taxes_item(sale_item, taxes, base_reduction, cst_icms)
        return sale_item




