from __future__ import annotations

import logging
from datetime import date
from decimal import Decimal
from typing import Any

from .sync_handlers import TruthSyncHandlersMixin

logger = logging.getLogger("dscons.invoice_truth.sync")


def to_decimal(val: Any) -> Decimal:
    if val is None:
        return Decimal("0.0000")
    try:
        return Decimal(str(val))
    except Exception:
        return Decimal("0.0000")


class TruthSyncMixin(TruthSyncHandlersMixin):
    """Extraction, normalization and synchronization from invoices into ground truth tables."""

    def extract_and_sync_all_truth(
        self, company_id: str | None = None, purge_drafts: bool = True
    ) -> dict[str, Any]:
        with self.get_connection() as conn:
            with conn.cursor() as cur:
                if not company_id:
                    cur.execute("SELECT id FROM companies LIMIT 1;")
                    c_row = cur.fetchone()
                    if c_row:
                        company_id = str(c_row["id"])
                    else:
                        cur.execute(
                            "INSERT INTO companies (name, tax_code) VALUES ('CÔNG TY TNHH XÂY DỰNG ĐỊNH SƠN', '0202111150') RETURNING id;"
                        )
                        company_id = str(cur.fetchone()["id"])

                purged_equipment_cnt = 0
                if purge_drafts:
                    cur.execute("""
                        DELETE FROM erp_equipment 
                        WHERE source_invoice_id IS NULL AND equipment_code NOT LIKE 'EQ-REAL-%';
                    """)
                    purged_equipment_cnt = cur.rowcount

                cur.execute("""
                    SELECT 
                        id, invoice_number, invoice_series, template_code,
                        issue_date, seller_name, seller_tax_code,
                        subtotal_amount_vnd, vat_amount_vnd, total_amount_vnd,
                        xml_raw_content, matched_project_id, matched_wbs_id
                    FROM erp_invoices
                    WHERE direction = 'input'
                    ORDER BY issue_date ASC;
                """)
                invoices = cur.fetchall()

                stats: dict[str, Any] = {
                    "total_invoices_scanned": len(invoices),
                    "equipment_assets_added": 0,
                    "rental_logs_added": 0,
                    "warehouse_materials_staged": 0,
                    "services_categorized": 0,
                    "purged_draft_equipment": purged_equipment_cnt,
                    "equipment_details": [],
                    "material_summary": {},
                }

                equipment_code_counter = 1
                material_code_counter = 1
                for inv in invoices:
                    inv_id = inv["id"]
                    series = inv["invoice_series"] or ""
                    inv_num = inv["invoice_number"] or ""
                    seller = inv["seller_name"] or ""
                    seller_mst = inv["seller_tax_code"] or ""
                    issue_dt = inv["issue_date"] or date.today()
                    xml_raw = inv["xml_raw_content"] or ""
                    project_id = inv["matched_project_id"]
                    wbs_id = inv["matched_wbs_id"]

                    cur.execute(
                        """
                        SELECT id, item_order, item_name, unit, quantity, unit_price_vnd, total_item_amount_vnd
                        FROM erp_invoice_items
                        WHERE invoice_id = %s
                        ORDER BY item_order ASC;
                    """,
                        (inv_id,),
                    )
                    db_items = cur.fetchall()

                    items_to_process = []
                    if db_items:
                        for it in db_items:
                            items_to_process.append(
                                {
                                    "id": str(it["id"]),
                                    "item_name": it["item_name"],
                                    "unit": it["unit"],
                                    "quantity": to_decimal(it["quantity"]),
                                    "unit_price": to_decimal(it["unit_price_vnd"]),
                                    "total_amount": to_decimal(
                                        it["total_item_amount_vnd"]
                                    ),
                                }
                            )
                    elif xml_raw.startswith("<?xml") or "<HDon>" in xml_raw:
                        from app.modules.invoices.application.invoice_processing_service import (
                            InvoiceProcessingService,
                        )

                        inv_svc = InvoiceProcessingService()
                        parsed = inv_svc.parse_xml_content(
                            xml_raw, source_channel="truth_extractor"
                        )
                        for idx, it in enumerate(parsed.get("items", []), start=1):
                            items_to_process.append(
                                {
                                    "id": None,
                                    "item_name": it.get("item_name", f"Hàng hóa {idx}"),
                                    "unit": it.get("unit", "Lô"),
                                    "quantity": to_decimal(it.get("quantity", 1)),
                                    "unit_price": to_decimal(
                                        it.get("unit_price_vnd", 0)
                                    ),
                                    "total_amount": to_decimal(
                                        it.get("total_amount_vnd", 0)
                                    ),
                                }
                            )
                    else:
                        items_to_process.append(
                            {
                                "id": None,
                                "item_name": f"Hàng hóa / Dịch vụ cung cấp bởi {seller}",
                                "unit": "Lô",
                                "quantity": Decimal("1.0000"),
                                "unit_price": to_decimal(inv["subtotal_amount_vnd"]),
                                "total_amount": to_decimal(inv["total_amount_vnd"]),
                            }
                        )

                    for item in items_to_process:
                        classification = self.classify_item(
                            item_name=item["item_name"],
                            unit=item["unit"],
                            quantity=item["quantity"],
                            unit_price=item["unit_price"],
                            total_amount=item["total_amount"],
                            seller_name=seller,
                        )
                        c_type = classification["classification"]
                        if c_type == "OWNED_EQUIPMENT":
                            eq_code = f"EQ-TRUTH-{classification['equipment_type'].upper()[:3]}-{equipment_code_counter:03d}"
                            equipment_code_counter += 1
                            self._sync_owned_equipment(
                                cur,
                                company_id,
                                inv_id,
                                series,
                                inv_num,
                                seller,
                                issue_dt,
                                project_id,
                                item,
                                classification,
                                eq_code,
                                stats,
                            )
                        elif c_type == "RENTAL_EQUIPMENT":
                            stats["rental_logs_added"] += 1
                        elif c_type == "WAREHOUSE_MATERIAL":
                            mat_group = classification["material_group"]
                            mat_code = (
                                f"MAT-{mat_group[:4]}-{material_code_counter:04d}"
                            )
                            material_code_counter += 1
                            self._sync_warehouse_material(
                                cur,
                                company_id,
                                mat_code,
                                item,
                                mat_group,
                                seller,
                                seller_mst,
                                inv_id,
                                series,
                                inv_num,
                                issue_dt,
                                project_id,
                                wbs_id,
                                stats,
                            )
                        else:
                            stats["services_categorized"] += 1

                conn.commit()
                logger.info(f"Completed Truth Extraction: {stats}")
                return {
                    "status": "success",
                    "message": f"Trích xuất thành công {stats['equipment_assets_added']} thiết bị sở hữu, {stats['warehouse_materials_staged']} lô vật tư nhập kho, và phân loại {stats['rental_logs_added']} ca máy thuê ngoài từ {stats['total_invoices_scanned']} hóa đơn mua vào.",
                    "stats": stats,
                }
