from typing import override

from bb_integrations_lib.pipelines.parsers.bbd_export_parser_utils import (
    Entity,
    build_lookups,
    get_entity_id,
    to_timezone,
)
from bb_integrations_lib.protocols.pipelines import Parser
from loguru import logger


class PDIOrderParser(Parser):
    def __init__(
        self,
        counterparties: list[dict],
        locations: list[dict],
        stores: list[dict],
        products: list[dict],
        drivers: list[dict],
        source_system: str | None = None,
        entity_overrides: dict[str, dict] | None = None,
        date_format: str = "%Y/%m/%d %H:%M",
    ):
        super().__init__(source_system=source_system)
        lookups = build_lookups(counterparties, locations, stores, products, drivers)
        self.cp_lkp = lookups["cp_lkp"]
        self.loc_lkp = lookups["loc_lkp"]
        self.store_lkp = lookups["store_lkp"]
        self.prod_lkp = lookups["prod_lkp"]
        self.driver_lkp = lookups["driver_lkp"]
        self.store_lkp_by_number = lookups["store_lkp_by_number"]

        self.entities: dict[str, Entity] = {
            "product": Entity(use_source_id=True, source_id_key="source_id"),
            "customer": Entity(use_source_id=True, source_id_key="source_id"),
            "carrier": Entity(use_source_id=True, source_id_key="source_id"),
            "vendor": Entity(use_source_id=True, source_id_key="source_id"),
            "location": Entity(use_source_id=True, source_id_key="source_id"),
            "driver_id": Entity(
                use_source_id=False,
                source_id_key="source_id",
                fallback_field="username",
            ),
            "driver_name": Entity(
                use_source_id=False, source_id_key="source_id", fallback_field="name"
            ),
            "store_number": Entity(
                use_source_id=False,
                source_id_key="site_id",
                fallback_field="store_number",
            ),
            "store_name": Entity(
                use_source_id=False, source_id_key="site_id", fallback_field="name"
            ),
        }
        if entity_overrides:
            for key, val in entity_overrides.items():
                self.entities[key] = Entity(**val)
        self.default_date_format = date_format

    def __repr__(self) -> str:
        return "PDI Order Parser"

    @override
    async def parse(self, data: list[dict]) -> tuple:
        rows: list[dict] = []
        errors: list[dict] = []
        processed: list[dict] = []

        for order in data:
            order_number = order.get("order_number")
            try:
                matched_allocations = order.get("matched_allocations", [])
                allocated_bols = order.get("allocated_bols", [])

                if len(allocated_bols) != len(matched_allocations):
                    logger.warning(
                        f"Order {order_number} has mismatched allocations and bols."
                    )

                for index, matched in enumerate(matched_allocations):
                    executed_drop = matched.get("executed_drop")
                    executed_bol = matched.get("executed_bol")
                    allocated_bol = matched.get("allocated_bol")

                    store = self.store_lkp_by_number.get(
                        executed_drop.get("location"), {}
                    )
                    store_tz = store.get("timezone")

                    customer_id = store.get("counterparty_id")
                    store_cp = self.cp_lkp.get(customer_id, {})

                    supplier = self.cp_lkp.get(allocated_bol.get("bol_supplier_id"), {})
                    terminal = self.loc_lkp.get(
                        allocated_bol.get("bol_terminal_id"), {}
                    )
                    product = self.prod_lkp.get(allocated_bol.get("bol_product_id"), {})
                    carrier = self.cp_lkp.get(order.get("carrier_id"), {})
                    driver_info = self.driver_lkp.get(
                        executed_drop.get("driver_id"), {}
                    )

                    bol_delivered_date = allocated_bol.get("bol_date")
                    delivery_date_time = (
                        to_timezone(dd, store_tz)
                        if (dd := bol_delivered_date) and store_tz
                        else None
                    )

                    executed_lift_time = executed_bol.get("date")
                    lift_date_time = (
                        to_timezone(lt, store_tz)
                        if (lt := executed_lift_time) and store_tz
                        else None
                    )

                    row = {
                        "Order #": order_number,
                        "Customer ID": get_entity_id(
                            self.entities, "customer", store_cp
                        ),
                        "Site ID": get_entity_id(self.entities, "store_number", store),
                        "Site Name": get_entity_id(self.entities, "store_name", store),
                        "Bill of Lading #": executed_bol.get("bol_number"),
                        "Delivery Date Time": (
                            delivery_date_time.strftime(self.default_date_format)
                            if delivery_date_time
                            else None
                        ),
                        "Carrier ID": get_entity_id(self.entities, "carrier", carrier),
                        "Vehicle ID": executed_drop.get("tractor_number"),
                        "Driver Name": get_entity_id(
                            self.entities, "driver_name", driver_info
                        ),
                        "Driver ID": get_entity_id(
                            self.entities, "driver_id", driver_info
                        ),
                        "Load Product ID": get_entity_id(
                            self.entities, "product", product
                        ),
                        "Origin Vendor ID": get_entity_id(
                            self.entities, "vendor", supplier
                        ),
                        "Origin Terminal ID": get_entity_id(
                            self.entities, "location", terminal
                        ),
                        "Lift Date Time": (
                            lift_date_time.strftime(self.default_date_format)
                            if lift_date_time
                            else None
                        ),
                        "Drop Product ID": get_entity_id(
                            self.entities, "product", product
                        ),
                        "Destination Tank No": allocated_bol.get("store_tank"),
                        "Ordered/Gross Delivered Quantity": allocated_bol.get(
                            "bol_gross_volume_allocated"
                        ),
                        "Load Gross Quantity": allocated_bol.get(
                            "bol_gross_volume_original"
                        ),
                        "Load Net Quantity": allocated_bol.get(
                            "bol_net_volume_original"
                        ),
                        "Net Delivered Quantity": allocated_bol.get(
                            "bol_net_volume_allocated"
                        ),
                        "Purchase Order Number": order.get("po"),
                        "Order Line Item No": index + 1,
                    }
                    rows.append(row)
                processed.append(order)
            except Exception as e:
                msg = f"Failed to parse order {order_number}: {e}"
                order["error_message"] = msg
                logger.warning(msg)
                errors.append(order)
                continue

        return rows, processed, errors
