import json
from typing import (
    Any,
    Dict,
)

from nreports.builders import DataBuilder
from nreports.utils import (
    convert_from_utf_to_localtime,
    format_customer_doc,
    get_logo_image_str,
)
from nreports_api.shared import JSON
from ._DeliveryOrderDto import DeliveryOrderDto


class DeliveryCouponBuilder(DataBuilder):

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

        pos_id = int(kwargs["posId"])
        order_id = int(kwargs["orderId"])
        delivery_order_dto = self._get_delivery_order_dto(
            pos_id=pos_id,
            order_id=order_id,
        )

        self._get_header_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )
        self._get_body_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )
        self._get_footer_data(data_to_build=data_to_build)

        font_size_small = self.constants.get("DELIVERY_REPORT_FONT_SIZE", "small").lower() == "small"
        data_to_build["DELIVERY_REPORT_FONT_SIZE_SMALL"] = font_size_small
        data_to_build["DELIVERY_REPORT_FONT_SIZE_LARGE"] = not font_size_small

        return data_to_build

    def _get_body_data(
        self,
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        self._get_customer_info_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
            show_customer_phone=self.constants.get("DELIVERY_COUPON_SHOW_CUSTOMER_PHONE", "false").lower() == "true",
        )
        self._get_items_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )
        self._get_totals_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )
        self._get_tenders_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )
        self._get_observations_data(
            data_to_build=data_to_build,
            delivery_order_dto=delivery_order_dto,
        )

    def _get_delivery_order_dto(
        self,
        pos_id: int,
        order_id: int,
    ) -> DeliveryOrderDto:

        order_service = self.order_api_repository.get_order_service(pos_id=pos_id)
        order_picture_xml = order_service.get_order_picture(order_id=order_id)

        delivery_json = order_picture_xml.find(".//OrderProperty[@key='REMOTE_ORDER_JSON']")
        if delivery_json is None:
            delivery_json = order_picture_xml.find(".//OrderProperty[@key='MANUAL_DELIVERY_ORDER_JSON']")
        delivery_json = json.loads(delivery_json.get("value"))

        return DeliveryOrderDto(
            order_picture_xml=order_picture_xml,
            delivery_json=delivery_json,
            product_repository=self.product_repository,
        )

    @staticmethod
    def _get_header_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        data_to_build["PARTNER_NAME"] = delivery_order_dto.display_partner.upper()
        data_to_build["SHORT_REFERENCE"] = delivery_order_dto.order_number
        data_to_build["ORDER_ID"] = delivery_order_dto.pos_order_id

        if delivery_order_dto.partner.lower() != "delivery":
            created_at = convert_from_utf_to_localtime(utc=delivery_order_dto.order_date)
        else:
            created_at = delivery_order_dto.order_date

        data_to_build["CREATED_AT"] = created_at.isoformat()

    @staticmethod
    def _get_customer_info_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
        show_customer_phone: bool,
    ) -> None:

        data_to_build["CUSTOMER_NAME"] = delivery_order_dto.customer_name
        if show_customer_phone and (delivery_order_dto.partner.lower() != "ifood" or delivery_order_dto.need_logistics):
            data_to_build["PHONE"] = delivery_order_dto.customer_phone

        data_to_build["ADDRESS"] = delivery_order_dto.address
        data_to_build["COMPLEMENT"] = delivery_order_dto.address_complement
        data_to_build["REFERENCE"] = delivery_order_dto.reference
        data_to_build["NEIGHBORHOOD"] = delivery_order_dto.address_neighborhood
        data_to_build["CITY"] = delivery_order_dto.city
        data_to_build["POSTAL_CODE"] = delivery_order_dto.postal_code

        if delivery_order_dto.take_out_order:
            data_to_build["TAKE_OUT_ORDER"] = True

    @staticmethod
    def _get_items_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        items = []
        for item in delivery_order_dto.items:
            items.append(
                {
                    "ITEM_PRODUCT_QUANTITY": item.quantity or "",
                    "ITEM_PRODUCT_NAME": item.product_name,
                    "ITEM_PRODUCT_VALUE": item.price or "",
                }
            )

        data_to_build["ITEM_PRODUCT"] = items

    @staticmethod
    def _get_totals_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        data_to_build["SUB_TOTAL_PRICE"] = delivery_order_dto.sub_total_price
        if not delivery_order_dto.take_out_order:
            data_to_build["DELIVERY_FEE"] = delivery_order_dto.delivery_fee
        data_to_build["ADDITIONAL_FEE"] = delivery_order_dto.additional_fee
        data_to_build["TOTAL_PRICE"] = delivery_order_dto.total_price

        vouchers = []
        for key, value in delivery_order_dto.vouchers.items():
            if float(value) > 0:
                vouchers.append({
                    "VOUCHER_NAME": key,
                    "VOUCHER_VALUE": value,
                })

        data_to_build["VOUCHER"] = vouchers or None

    @staticmethod
    def _get_tenders_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        tenders = []
        for tender in delivery_order_dto.tenders:
            tenders.append(
                {
                    "TENDER_DESCRIPTION": tender.tender_type,
                    "TENDER_VALUE": tender.value,
                }
            )

            if tender.tender_type_description:
                tenders.append(
                    {
                        "TENDER_DESCRIPTION": tender.tender_type_description,
                        "TENDER_VALUE": tender.tender_change_amount or "",
                    }
                )

        data_to_build["TENDER"] = tenders

    @staticmethod
    def _get_observations_data(
        data_to_build: Dict[str, JSON],
        delivery_order_dto: DeliveryOrderDto,
    ) -> None:

        observations = []
        if delivery_order_dto.observation:
            for observation in delivery_order_dto.observation.split(";"):
                observations.append(
                    {
                        "OBSERVATION_DESCRIPTION": observation.strip(),
                    }
                )

        data_to_build["OBSERVATION"] = observations or None

        if delivery_order_dto.customer_doc:
            data_to_build["CUSTOMER_DOC"] = format_customer_doc(document=delivery_order_dto.customer_doc)

        data_to_build["ORDER_OBSERVATION"] = delivery_order_dto.observations or None

    def _get_footer_data(
        self,
        data_to_build: Dict[str, JSON],
    ) -> None:

        image_path = self.images_path["3S_CHECKOUT_LOGO_FOOTER"]
        if not image_path:
            return

        data_to_build["STORE_IMG_LOGO"] = get_logo_image_str(
            image_path=image_path,
            base_width=250,
        )
