from __future__ import annotations

"""GDT on-demand XML enrichment scraper."""


import json
import logging
import ssl
import urllib.error
import urllib.parse
import urllib.request
import uuid
from decimal import ROUND_HALF_UP, Decimal
from typing import Any

from .helpers import to_decimal

logger = logging.getLogger(__name__)


class InvoiceGdtDetailEnrichMixin:
    """Mixin for on-demand detail enrichment."""

    def _enrich_gdt_invoice_detail_on_demand(
        self, invoice_id: str, inv_data: dict[str, Any]
    ) -> dict[str, Any] | None:
        """Tải chi tiết đầy đủ danh mục hàng hóa / dịch vụ từ Cổng Tổng Cục Thuế khi người dùng mở xem hóa đơn."""
        try:
            seller_tax_code = inv_data.get("seller_tax_code", "")
            invoice_series = inv_data.get("invoice_series", "")
            template_code = str(inv_data.get("template_code", "1"))
            inv_num_raw = str(inv_data.get("invoice_number", "1")).lstrip("0") or "1"

            # Clean series if needed (e.g. 1C23TYY -> C23TYY)
            khh_clean = invoice_series.removeprefix(template_code)

            configs = self.get_sync_configs()
            gdt_cfg = next(
                (c for c in configs if c["service_type"] == "gdt_portal"), None
            )
            if not gdt_cfg or not gdt_cfg.get("is_active", True):
                return None

            with self.get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        "SELECT password_hash, extra_config FROM erp_invoice_sync_configs WHERE id = %s",
                        (gdt_cfg["id"],),
                    )
                    row = cur.fetchone()
                    password = row["password_hash"]
                    extra = row.get("extra_config") if isinstance(row, dict) else {}

            auth_res = self._authenticate_gdt_portal(
                gdt_cfg["tax_code"], gdt_cfg["username"], password, extra_config=extra
            )

            if auth_res.get("status") != "success" or not auth_res.get("token"):
                return None

            token = auth_res["token"]
            cookie_header = auth_res.get("cookie_header") or ""
            ctx = ssl.create_default_context()
            ctx.check_hostname = False
            ctx.verify_mode = ssl.CERT_NONE

            headers = {
                "Authorization": f"Bearer {token}",
                "Cookie": cookie_header,
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36",
                "Accept": "application/json, text/plain, */*",
                "Referer": "https://hoadondientu.gdt.gov.vn/tra-cuu/tra-cuu-hoa-don",
                "Origin": "https://hoadondientu.gdt.gov.vn",
                "request-id": str(uuid.uuid4()),
                "end-point": "/tra-cuu/tra-cuu-hoa-don",
                "action": urllib.parse.quote("Xem chi tiết hóa đơn"),
            }

            gdt_id = None
            raw_saved = inv_data.get("xml_raw_content") or ""
            if raw_saved.startswith("{"):
                try:
                    raw_obj = json.loads(raw_saved)
                    gdt_id = raw_obj.get("id")
                except Exception:
                    pass

            candidate_urls = []
            if gdt_id:
                candidate_urls.append(
                    f"https://hoadondientu.gdt.gov.vn/api/query/invoices/detail?id={gdt_id}"
                )
            candidate_urls.append(
                f"https://hoadondientu.gdt.gov.vn/api/query/invoices/detail?nbmst={seller_tax_code}&khhdon={khh_clean}&shdon={inv_num_raw}&khmshdon={template_code}"
            )

            raw_d = None
            for url in candidate_urls:
                try:
                    headers["request-id"] = str(uuid.uuid4())
                    req = urllib.request.Request(url, headers=headers)
                    with urllib.request.urlopen(req, timeout=12, context=ctx) as res:
                        raw_d = json.loads(res.read().decode("utf-8"))
                        if raw_d and (raw_d.get("hdhhdvu") or raw_d.get("thttltsuat")):
                            break
                except urllib.error.HTTPError as he:
                    logger.warning("[GDT_ENRICH] HTTP error on %s: %s", url, he)
                    if he.code in (401, 403):
                        logger.warning("[GDT_ENRICH] Bị chặn bởi WAF (HTTP %s). Ngắt phiên ngay lập tức để bảo vệ tài khoản.", he.code)
                        break
                    continue
                except Exception as e:
                    logger.warning("[GDT_ENRICH] Exception on %s: %s", url, e)
                    continue

            if not raw_d:
                return None

            raw_items = raw_d.get("hdhhdvu", [])
            if not raw_items:
                # Fallback to thttltsuat if present
                thttltsuat = raw_d.get("thttltsuat") or []
                if thttltsuat and isinstance(thttltsuat, list) and len(thttltsuat) > 0:
                    raw_items = []
                    for idx, vb in enumerate(thttltsuat, start=1):
                        t_rate = str(vb.get("tsuat") or "8%").replace("%", "").strip()
                        t_amt = to_decimal(vb.get("thtien"), default=Decimal("0.0000"))
                        t_vat = to_decimal(vb.get("tthue"), default=Decimal("0.0000"))
                        raw_items.append({
                            "stt": idx,
                            "ten": f"Cung cấp hàng hóa, dịch vụ theo HĐ {inv_data.get('invoice_number')} ({inv_data.get('invoice_series')})",
                            "mhhdvu": f"GDT-SUM-{idx:02d}",
                            "dvtinh": "Gói",
                            "sluong": 1,
                            "dgia": float(t_amt),
                            "thtien": float(t_amt),
                            "ltsuat": f"{t_rate}%",
                            "tthue": float(t_vat),
                        })
                else:
                    return None

            seller_addr = str(
                raw_d.get("nbdchi") or inv_data.get("seller_address") or ""
            ).strip()
            buyer_addr = str(
                raw_d.get("nmdchi") or inv_data.get("buyer_address") or ""
            ).strip()
            amount_in_words = str(
                raw_d.get("tgtttbchu") or inv_data.get("amount_in_words") or ""
            ).strip()
            signed_by = str(
                raw_d.get("nbcks")
                or inv_data.get("signed_by")
                or inv_data.get("seller_name")
                or ""
            ).strip()

            total_val = (
                raw_d.get("tgtttbso")
                or raw_d.get("tgtttgthue")
                or inv_data.get("total_amount_vnd")
            )
            vat_val = raw_d.get("tgtthue") or inv_data.get("vat_amount_vnd") or 0

            total_amount_header = to_decimal(total_val)
            vat_amount_header = to_decimal(vat_val)

            thttltsuat = raw_d.get("thttltsuat") or []
            if thttltsuat and isinstance(thttltsuat, list) and len(thttltsuat) > 0:
                subtotal_header = sum(
                    to_decimal(b.get("thtien", 0)) for b in thttltsuat
                )
                calc_vat = sum(to_decimal(b.get("tthue", 0)) for b in thttltsuat)
                if calc_vat > 0:
                    vat_amount_header = calc_vat
            elif raw_d.get("tgtttbthue"):
                subtotal_header = to_decimal(raw_d.get("tgtttbthue"))
            else:
                subtotal_header = (
                    (total_amount_header - vat_amount_header)
                    if total_amount_header >= vat_amount_header
                    else Decimal("0.0000")
                )

            if total_amount_header == Decimal("0.0000") and (
                subtotal_header > 0 or vat_amount_header > 0
            ):
                total_amount_header = subtotal_header + vat_amount_header

            with self.get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        """
                        UPDATE erp_invoices
                        SET seller_address = %s,
                            buyer_address = %s,
                            amount_in_words = %s,
                            signed_by = %s,
                            subtotal_amount_vnd = %s,
                            vat_amount_vnd = %s,
                            total_amount_vnd = %s,
                            xml_raw_content = %s,
                            updated_at = CURRENT_TIMESTAMP
                        WHERE id = %s;
                    """,
                        (
                            seller_addr,
                            buyer_addr,
                            amount_in_words,
                            signed_by,
                            subtotal_header,
                            vat_amount_header,
                            total_amount_header,
                            json.dumps(raw_d, ensure_ascii=False),
                            invoice_id,
                        ),
                    )

                    # Replace generic items with genuine line items
                    cur.execute(
                        "DELETE FROM erp_invoice_items WHERE invoice_id = %s;",
                        (invoice_id,),
                    )

                    insert_item_sql = """
                        INSERT INTO erp_invoice_items (
                            invoice_id, item_order, item_name, item_code, unit, quantity,
                            unit_price_vnd, amount_before_vat_vnd, vat_rate_percent, vat_amount_vnd,
                            total_item_amount_vnd, cost_category
                        ) VALUES (
                            %s, %s, %s, %s, %s, %s,
                            %s, %s, %s, %s, %s, %s
                        );
                    """
                    for itm in raw_items:
                        stt = int(itm.get("stt") or 1)
                        name = str(itm.get("ten") or "Hàng hóa / Dịch vụ").strip()
                        code = str(itm.get("mhhdvu") or itm.get("id") or "").strip()
                        unit = str(itm.get("dvtinh") or "Gói").strip()
                        qty = to_decimal(itm.get("sluong"), default=Decimal("0.0000"))
                        unit_price = to_decimal(
                            itm.get("dgia"), default=Decimal("0.0000")
                        )
                        amount_before = to_decimal(
                            itm.get("thtien"), default=Decimal("0.0000")
                        )

                        vat_str = (
                            str(itm.get("ltsuat") or "8%").replace("%", "").strip()
                        )
                        try:
                            vat_rate = to_decimal(vat_str, default=Decimal("8.0000"))
                        except Exception:
                            vat_rate = Decimal("8.0000")

                        vat_amt = (
                            to_decimal(itm.get("tthue"))
                            if itm.get("tthue") is not None
                            else ((amount_before * vat_rate) / Decimal(100)).quantize(
                                Decimal("0.0001"), rounding=ROUND_HALF_UP
                            )
                        )
                        tot_amt = amount_before + vat_amt
                        cost_cat = self.categorize_item_cost(name, code)

                        cur.execute(
                            insert_item_sql,
                            (
                                invoice_id,
                                stt,
                                name,
                                code,
                                unit,
                                qty,
                                unit_price,
                                amount_before,
                                vat_rate,
                                vat_amt,
                                tot_amt,
                                cost_cat,
                            ),
                        )

                    conn.commit()

            logger.info(
                f"Enriched invoice {invoice_id} with {len(raw_items)} genuine line items from GDT."
            )

            # Re-read from DB
            with self.get_connection() as conn:
                with conn.cursor() as cur:
                    cur.execute(
                        """
                        SELECT
                            i.*,
                            p.project_name AS matched_project_name,
                            p.project_code AS matched_project_code,
                            w.wbs_code AS matched_wbs_code,
                            w.task_name AS matched_wbs_task_name
                        FROM erp_invoices i
                        LEFT JOIN projects p ON i.matched_project_id = p.id
                        LEFT JOIN erp_project_wbs w ON i.matched_wbs_id = w.id
                        WHERE i.id = %s
                    """,
                        (invoice_id,),
                    )
                    inv_row = cur.fetchone()
                    if not inv_row:
                        return None
                    inv_data = dict(inv_row)
                    inv_data["id"] = str(inv_data["id"])
                    if inv_data.get("matched_project_id"):
                        inv_data["matched_project_id"] = str(
                            inv_data["matched_project_id"]
                        )
                    if inv_data.get("matched_wbs_id"):
                        inv_data["matched_wbs_id"] = str(inv_data["matched_wbs_id"])
                    if inv_data.get("issue_date"):
                        inv_data["issue_date"] = str(inv_data["issue_date"])
                    if inv_data.get("signed_at"):
                        inv_data["signed_at"] = str(inv_data["signed_at"])
                    if inv_data.get("created_at"):
                        inv_data["created_at"] = str(inv_data["created_at"])
                    if inv_data.get("updated_at"):
                        inv_data["updated_at"] = str(inv_data["updated_at"])

                    for num_col in (
                        "subtotal_amount_vnd",
                        "vat_rate_percent",
                        "vat_amount_vnd",
                        "total_amount_vnd",
                        "exchange_rate",
                    ):
                        if num_col in inv_data and inv_data[num_col] is not None:
                            inv_data[num_col] = float(inv_data[num_col])

                    cur.execute(
                        "SELECT * FROM erp_invoice_items WHERE invoice_id = %s ORDER BY item_order ASC",
                        (invoice_id,),
                    )
                    item_rows = cur.fetchall()
                    items_enr: list[dict[str, Any]] = []
                    for itm in item_rows:
                        idict = dict(itm)
                        idict["id"] = str(idict["id"])
                        idict["invoice_id"] = str(idict["invoice_id"])
                        for num_col in (
                            "quantity",
                            "unit_price_vnd",
                            "amount_before_vat_vnd",
                            "vat_rate_percent",
                            "vat_amount_vnd",
                            "total_item_amount_vnd",
                        ):
                            if num_col in idict and idict[num_col] is not None:
                                idict[num_col] = float(idict[num_col])
                        items_enr.append(idict)
                    inv_data["items"] = items_enr
                    return inv_data

        except Exception as e:
            logger.warning(
                f"Error in on-demand enrichment for invoice {invoice_id}: {e}"
            )
            return None
