# import schema definition
from collections import defaultdict
from datetime import date
from typing import Sequence

from src.data.model.db.partner_agent import Order as DB_Order, OrderDetail as DB_OrderDetail
from src.data.exports.schema.order import (
    SalesOrderTypeSub as SalesOrder,
    TypeTypeSub as SalesOrderType,
    semiramisSub as Header,
    customerDataTypeSub as CustomerData,
    CustomerPartnerTypeSub as CustomerPartner,
    customerOrderDataTypeSub as CustomerOrder,
    invoicingPartyDataTypeSub as InvoicingData,
    PartnerTypeSub as Partner,
    DetailsTypeSub as SalesOrderDetail,
    totalQuantityTypeSub as Quantity,
    UomTypeSub as Uom,
    dateFromTypeSub as DateFrom,
    dateUntilTypeSub as DateTo,
    imp_deliveryDateTypeSub as DeliveryDate,
    ItemTypeSub as Item,
    Imp_ColorTypeSub as Color,
    Imp_SizeTypeSub as Size,
    ReferenceItemTypeSub as ReferenceItem,
    SizeRegisterTypeSub as SizeRegister
)
from loguru import logger
from src.data.model.schemas.base_schemas import BaseSchemaModel

from src.data.model.schemas import Shop


class OrderDetail(BaseSchemaModel):
    quantity: int
    date_from: date
    date_to: date
    color: str
    size: str
    size_register: int
    reference_item_number: str


class Order(BaseSchemaModel):
    id: int
    type: int
    partner: int
    details: list[OrderDetail]
    #shop: Shop


def preprocess_order(unprocessed_order: Sequence[DB_Order]) -> list[Order]:
    def preprocess_order_details(details: list[DB_OrderDetail]) -> list[OrderDetail]:
        return [
            OrderDetail(
                quantity=detail.quantity,
                date_from=detail.article_detail.article.delivery_date_from,
                date_to=detail.article_detail.article.delivery_date_to,
                color=detail.article_detail.color.code,
                size=detail.article_detail.size,
                size_register=detail.article_detail.size_register,
                reference_item_number=detail.article_detail.article_number,
            )
            for detail in details
        ]

    for order in unprocessed_order:
        grouped_by_order_type = defaultdict(list[DB_OrderDetail])
        # set shipping price
        for detail in order.details:
            grouped_by_order_type[detail.sales_order_type_code].append(detail)

        for sales_order_type, details in grouped_by_order_type.items():
            yield sales_order_type, Order(
                id=order.id,
                type=sales_order_type,
                partner=order.partner_id,
                details=preprocess_order_details(details)
            )


def generate_xml(unprocessed_order: Sequence[DB_Order]) -> str:
    order_numbers = map(lambda o: o.id, unprocessed_order)
    logger.info(f"Exporting order {order_numbers}")

    # create xml export
    xml = Header()
    xml.set_locale("en-US-XMLSchemaCompliant")
    xml.set_nlsMode("SINGLE_LANGUAGE")
    xml.set_dateTimeMode("NORMALIZED")
    for sales_order_type, order in preprocess_order(unprocessed_order):
        sales_order_xml = SalesOrder()
        # sales order type
        sales_order_xml.set_Type(SalesOrderType(code=sales_order_type))
        # customer data
        sales_order_xml.set_customerData(CustomerData(CustomerPartner=CustomerPartner(number=order.partner)))
        # order number
        sales_order_xml.set_customerOrderData(CustomerOrder(purchaseOrder=f"{order.id}-0"))
        # invoicing data
        sales_order_xml.set_invoicingPartyData(invoicingPartyData=InvoicingData(Partner=Partner(number=999991)))
        # details
        for detail in order.details:
            delivery_date = None
            if sales_order_type != "201":
                delivery_date = DeliveryDate(
                    dateFrom=DateFrom(specialValue="NONE", date=detail.date_from, timeZone="CET"),
                    dateUntil=DateTo(specialValue="NONE", date=detail.date_to, timeZone="CET")
                )
            # to clarify: recommended gross price
            sales_order_xml.add_Details(
                SalesOrderDetail(
                    totalQuantity=Quantity(amount=detail.quantity, Uom=Uom(code="stk")),
                    priceOriginType="DEFINITION",
                    imp_deliveryDate=delivery_date,
                    Item=Item(
                        materialType="VARIANT_ITEM",
                        Imp_Color=Color(
                            code=detail.color,
                            collectionFlag="false"
                        ),
                        Imp_Size=Size(
                            code=detail.size,
                            SizeRegister=SizeRegister(code=detail.size_register)
                        ),
                        ReferenceItem=ReferenceItem(
                            number=detail.reference_item_number
                        ),
                    )
                )
            )
            xml.add_SalesOrder(sales_order_xml)

        return str(xml)
