import datetime
from typing import List
from uuid import uuid4
from xml.dom import minidom
from xml.etree.ElementTree import Element, SubElement, tostring

from vbv_lernwelt.shop.invoice.creator import InvoiceCreator, Item
from vbv_lernwelt.shop.invoice.repositories import InvoiceRepository
from vbv_lernwelt.shop.models import CheckoutInformation


class AbacusInvoiceCreator(InvoiceCreator):
    def __init__(self, repository: InvoiceRepository):
        self.repository = repository

    def create_invoice(
        self,
        checkout_information: CheckoutInformation,
        filename: str = None,
    ):
        customer_number = checkout_information.transaction_id
        order_date = checkout_information.created_at.date()
        reference_purchase_order = str(checkout_information.id)
        unic_id = checkout_information.transaction_id

        items = [
            Item(
                product_number=checkout_information.product_sku,
                quantity=1,
                description=checkout_information.product_description,
            )
        ]

        invoice = self.invoice_xml(
            customer_number,
            order_date,
            reference_purchase_order,
            unic_id,
            items,
        )

        if filename is None:
            filename = f"vbv-vv-{uuid4().hex}.xml"

        self.repository.upload_invoice(invoice, filename)

    @staticmethod
    def invoice_xml(
        customer_number: str,
        order_date: datetime.date,
        reference_purchase_order: str,
        unic_id: str,
        items: List[Item],
    ) -> str:
        container = Element("AbaConnectContainer")
        task = SubElement(container, "Task")
        parameter = SubElement(task, "Parameter")
        SubElement(parameter, "Application").text = "ORDE"
        SubElement(parameter, "Id").text = "Verkaufsauftrag"
        SubElement(parameter, "MapId").text = "AbaDefault"
        SubElement(parameter, "Version").text = "2022.00"

        transaction = SubElement(task, "Transaction")
        sales_order_header = SubElement(transaction, "SalesOrderHeader", mode="SAVE")
        sales_order_header_fields = SubElement(
            sales_order_header, "SalesOrderHeaderFields", mode="SAVE"
        )

        SubElement(sales_order_header_fields, "CustomerNumber").text = customer_number
        SubElement(
            sales_order_header_fields, "PurchaseOrderDate"
        ).text = order_date.isoformat()
        SubElement(
            sales_order_header_fields, "DeliveryDate"
        ).text = order_date.isoformat()
        SubElement(
            sales_order_header_fields, "ReferencePurchaseOrder"
        ).text = reference_purchase_order
        SubElement(sales_order_header_fields, "UnicId").text = unic_id

        for index, item in enumerate(items, start=1):
            item_element = SubElement(sales_order_header, "Item", mode="SAVE")
            item_fields = SubElement(item_element, "ItemFields", mode="SAVE")
            SubElement(item_fields, "ItemNumber").text = str(index)
            SubElement(item_fields, "ProductNumber").text = item.product_number
            SubElement(item_fields, "QuantityOrdered").text = str(item.quantity)

            item_text = SubElement(item_element, "ItemText", mode="SAVE")
            item_text_fields = SubElement(item_text, "ItemTextFields", mode="SAVE")
            SubElement(item_text_fields, "Text").text = item.description

        return AbacusInvoiceCreator.create_xml_string(container)

    @staticmethod
    def customer_xml(
        customer_number: str,
        name: str,
        first_name: str,
        address_text: str,
        street: str,
        house_number: str,
        zip_code: str,
        city: str,
        country: str,
        language: str,
        email: str,
    ):
        container = Element("AbaConnectContainer")
        task = SubElement(container, "Task")

        parameter = SubElement(task, "Parameter")
        SubElement(parameter, "Application").text = "DEBI"
        SubElement(parameter, "ID").text = "Kunden"
        SubElement(parameter, "MapID").text = "AbaDefault"
        SubElement(parameter, "Version").text = "2022.00"

        transaction = SubElement(task, "Transaction")
        customer_element = SubElement(transaction, "Customer", mode="SAVE")

        SubElement(customer_element, "CustomerNumber").text = customer_number
        SubElement(customer_element, "DefaultCurrency").text = "CHF"
        SubElement(customer_element, "PaymentTermNumber").text = "1"
        SubElement(customer_element, "ReminderProcedure").text = "NORM"

        address_data = SubElement(customer_element, "AddressData", mode="SAVE")
        SubElement(address_data, "AddressNumber").text = customer_number
        SubElement(address_data, "Name").text = name
        SubElement(address_data, "FirstName").text = first_name
        SubElement(address_data, "Text").text = address_text
        SubElement(address_data, "Street").text = street
        SubElement(address_data, "HouseNumber").text = house_number
        SubElement(address_data, "ZIP").text = zip_code
        SubElement(address_data, "City").text = city
        SubElement(address_data, "Country").text = country
        SubElement(address_data, "Language").text = language
        SubElement(address_data, "Email").text = email

        return AbacusInvoiceCreator.create_xml_string(container)

    @staticmethod
    def create_xml_string(container: Element, encoding: str = "UTF-8") -> str:
        xml_bytes = tostring(container, encoding)
        xml_pretty_str = minidom.parseString(xml_bytes).toprettyxml(
            indent="  ", encoding=encoding
        )
        return xml_pretty_str.decode(encoding)
