from __future__ import annotations

import logging
from datetime import datetime
from typing import Any

logger = logging.getLogger(__name__)


class Invoice3WayMatchingMixin:
    """Mixin for 3-way matching (Invoice vs Purchase Order vs Goods Receipt Note)."""

    def audit_3way_matching(self, invoice_id: str) -> dict[str, Any]:
        """Thực hiện đối soát 3-way cho hóa đơn với Đơn đặt hàng (PO) và Phiếu nhập kho (GRN)."""
        inv = self.get_invoice_detail(invoice_id)
        if not inv:
            return {"status": "error", "message": "Không tìm thấy hóa đơn cần rà soát."}

        invoice_number = inv.get("invoice_number")
        seller_tax_code = inv.get("seller_tax_code")

        # Query POs linked to this seller
        sql = """
            SELECT po_number, total_amount_vnd, status 
            FROM erp_purchase_orders 
            WHERE vendor_tax_code = %s AND (invoice_reference = %s OR status = 'fulfilled')
        """
        pos = []
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(sql, (seller_tax_code, invoice_number))
                pos = cur.fetchall()
        except Exception as e:
            logger.warning(f"Không thể truy vấn PO: {e}")

        # Query GRNs
        sql_grn = """
            SELECT grn_number, receipt_date, total_received_value 
            FROM erp_goods_receipt_notes 
            WHERE vendor_tax_code = %s AND invoice_reference = %s
        """
        grns = []
        try:
            with self.get_connection() as conn, conn.cursor() as cur:
                cur.execute(sql_grn, (seller_tax_code, invoice_number))
                grns = cur.fetchall()
        except Exception as e:
            logger.warning(f"Không thể truy vấn GRN: {e}")

        match_flags = []
        risk_score = 0
        total_inv_amount = float(inv.get("total_amount_vnd") or 0.0)

        # Check PO
        if not pos:
            match_flags.append({
                "type": "PO_MISSING",
                "severity": "medium",
                "message": "Không tìm thấy Đơn đặt hàng (PO) nào khớp với nhà cung cấp hoặc số hóa đơn này."
            })
            risk_score += 15
        else:
            po_total = sum(float(po.get("total_amount_vnd") or 0.0) for po in pos)
            diff = abs(total_inv_amount - po_total)
            if diff > 1000:
                match_flags.append({
                    "type": "PO_AMOUNT_MISMATCH",
                    "severity": "high",
                    "message": f"Giá trị hóa đơn lệch so với tổng PO."
                })
                risk_score += 30
            else:
                match_flags.append({
                    "type": "PO_MATCHED",
                    "severity": "safe",
                    "message": f"Giá trị hóa đơn khớp với Đơn đặt hàng."
                })

        # Check GRN
        if not grns:
            match_flags.append({
                "type": "GRN_MISSING",
                "severity": "high",
                "message": "Chưa có Phiếu nhập kho (GRN) thực tế cho hóa đơn này."
            })
            risk_score += 40
        else:
            grn_total = sum(float(g.get("total_received_value") or 0.0) for g in grns)
            diff = abs(total_inv_amount - grn_total)
            if diff > 1000:
                match_flags.append({
                    "type": "GRN_AMOUNT_MISMATCH",
                    "severity": "high",
                    "message": f"Giá trị hóa đơn lệch so với Phiếu nhập kho."
                })
                risk_score += 30
            else:
                match_flags.append({
                    "type": "GRN_MATCHED",
                    "severity": "safe",
                    "message": f"Giá trị hóa đơn khớp với Phiếu nhập kho."
                })

        status = "DRAFT"
        if risk_score == 0:
            status = "3WAY_MATCHED"
            try:
                with self.get_connection() as conn, conn.cursor() as cur:
                    cur.execute("UPDATE erp_invoices SET status = 'approved' WHERE id = %s", (invoice_id,))
                    conn.commit()
            except Exception:
                pass

        return {
            "invoice_id": invoice_id,
            "invoice_number": invoice_number,
            "3way_status": status,
            "match_flags": match_flags,
            "risk_score": risk_score,
            "audit_timestamp": datetime.now().isoformat(),
        }
