from __future__ import annotations

"""AI QS Automated Audit & Compliance Quality Engine for BoQ Takeoffs.
Inspects 100% BoQ line items against structural balance rules, norm codes,
omissions (formwork, rebar, site drainage), and price ceilings.
"""

import logging
from typing import Any

logger = logging.getLogger("dscons.takeoff.audit_engine")


class BoqAuditEngine:
    """Automated Quality Assurance & Compliance Audit for Construction BoQ."""

    @classmethod
    def audit_takeoff(
        cls,
        items: list[dict[str, Any]],
        drawing_type: str = "civil_building",
        takeoff_title: str = "Hồ sơ bóc tách bản vẽ",
    ) -> dict[str, Any]:
        """Perform comprehensive structural and regulatory audit on BoQ items."""
        findings: list[dict[str, Any]] = []
        healed_recommendations: list[dict[str, Any]] = []

        total_concrete_m3 = 0.0
        total_formwork_m2 = 0.0
        total_rebar_kg = 0.0
        total_excavation_m3 = 0.0
        total_backfill_m3 = 0.0

        has_piling_or_sheet = False
        has_drainage_pumping = False
        has_lean_concrete = False

        for idx, itm in enumerate(items):
            name = str(itm.get("item_name") or "").lower()
            cat = str(itm.get("category") or "").lower()
            qty = float(itm.get("quantity") or 0.0)
            unit = str(itm.get("unit") or "").lower()
            price = float(itm.get("unit_price_vnd") or itm.get("unit_price") or 0.0)

            # Check 1: Zero or Negative quantity / price
            if qty <= 0:
                findings.append(
                    {
                        "severity": "critical",
                        "code": "AUDIT-001",
                        "item_order": idx + 1,
                        "item_name": itm.get("item_name"),
                        "title": "Khối lượng công tác bằng 0 hoặc âm",
                        "description": f"Công tác '{itm.get('item_name')}' có khối lượng là {qty}. Cần kiểm tra lại hình học bản vẽ.",
                        "suggestion": "Điền khối lượng giải tích hình học hợp lệ.",
                    }
                )

            if price <= 0:
                findings.append(
                    {
                        "severity": "warning",
                        "code": "AUDIT-002",
                        "item_order": idx + 1,
                        "item_name": itm.get("item_name"),
                        "title": "Đơn giá công tác chưa được thiết lập",
                        "description": f"Công tác '{itm.get('item_name')}' có đơn giá = 0 VNĐ.",
                        "suggestion": "Tự động tra cứu đơn giá Sở Xây Dựng Hải Phòng.",
                    }
                )

            # Check 2: Unit anomalies (e.g. rebar with m2 or concrete with kg)
            is_rebar = "cốt thép" in name or (
                "thép" in name
                and "cừ" not in name
                and "ván" not in name
                and "dây" not in name
                and "buộc" not in name
                and "ống" not in name
            )
            if is_rebar:
                if unit not in ["kg", "tấn", "tan", "t", "m", "md"]:
                    findings.append(
                        {
                            "severity": "critical",
                            "code": "AUDIT-003",
                            "item_order": idx + 1,
                            "item_name": itm.get("item_name"),
                            "title": "Sai lệch Đơn vị tính Cốt thép",
                            "description": f"Công tác cốt thép đang có ĐVT là '{unit}', bắt buộc phải là 'kg' hoặc 'tấn'.",
                            "suggestion": "Quy đổi về ĐVT 'tấn' hoặc 'kg' chuẩn TCVN.",
                        }
                    )
                total_rebar_kg += (
                    (qty * 1000.0)
                    if ("tấn" in unit or "tan" in unit or unit == "t")
                    else qty
                )

            elif ("bê tông" in name or "btct" in name) and not any(
                k in name
                for k in ["lắp", "lắp đặt", "cấu kiện", "đoạn ống", "bốc", "vận chuyển"]
            ):
                if "lót" in name or "m100" in name:
                    has_lean_concrete = True
                if unit not in ["m3", "100m3"]:
                    findings.append(
                        {
                            "severity": "critical",
                            "code": "AUDIT-004",
                            "item_order": idx + 1,
                            "item_name": itm.get("item_name"),
                            "title": "Sai lệch Đơn vị tính Bê tông",
                            "description": f"Công tác bê tông đang có ĐVT là '{unit}', bắt buộc phải là 'm3'.",
                            "suggestion": "Chuyển về ĐVT 'm3'.",
                        }
                    )
                total_concrete_m3 += qty * (100.0 if "100m3" in unit else 1.0)

            elif "ván khuôn" in name or "van khuon" in name:
                total_formwork_m2 += qty * (100.0 if "100m2" in unit else 1.0)

            elif "đào" in name or "nạo vét" in name:
                total_excavation_m3 += qty

            elif "đắp" in name or "hoàn trả" in name:
                total_backfill_m3 += qty

            elif "cọc" in name or "cừ" in name or "larsen" in name:
                has_piling_or_sheet = True

            elif (
                "bơm" in name
                or "rãnh tiêu" in name
                or "đê quai" in name
                or "hạ mực" in name
            ):
                has_drainage_pumping = True

        # Check 3: Structural balance (Concrete vs Formwork)
        if total_concrete_m3 > 5.0 and total_formwork_m2 <= 0.0:
            findings.append(
                {
                    "severity": "critical",
                    "code": "AUDIT-010",
                    "title": "Thiếu toàn bộ công tác Ván khuôn kết cấu",
                    "description": f"Tổng thể tích bê tông là {total_concrete_m3:.2f} m3 nhưng hồ sơ chưa có ván khuôn tiếp xúc.",
                    "suggestion": "Tự động bổ sung công tác 'Ván khuôn định hình thi công bê tông'.",
                }
            )
            healed_recommendations.append(
                {
                    "wbs_code": "VK-SUPPLEMENT",
                    "norm_code": "AF.81110",
                    "item_name": "Ván khuôn định hình thép thi công kết cấu bê tông (Tự động bổ sung)",
                    "category": "formwork",
                    "dimension_formula": f"Tính theo định mức diện tích tiếp xúc ({total_concrete_m3:.2f} m3 * 0.85 m2/m3)",
                    "unit": "m2",
                    "quantity": round(total_concrete_m3 * 0.85, 2),
                    "unit_price_vnd": 145000,
                    "total_amount_vnd": round(total_concrete_m3 * 0.85 * 145000, 0),
                }
            )

        # Check 4: Concrete without Lean Concrete (Bê tông lót)
        if total_concrete_m3 > 10.0 and not has_lean_concrete:
            findings.append(
                {
                    "severity": "warning",
                    "code": "AUDIT-011",
                    "title": "Chưa có công tác Bê tông lót móng / đáy kết cấu",
                    "description": "Theo TCVN và Định mức 2026, đáy móng/cống phải có lớp bê tông lót M100 đá 4x6 dày 10cm.",
                    "suggestion": "Bổ sung công tác Bê tông lót đáy móng đá 4x6 M100 dày 10cm.",
                }
            )
            healed_recommendations.append(
                {
                    "wbs_code": "LOT-SUPPLEMENT",
                    "norm_code": "AF.11110",
                    "item_name": "Bê tông lót móng đá 4x6 M100 dày 10cm (Tự động bổ sung)",
                    "category": "concrete",
                    "dimension_formula": f"Đáy móng dày 10cm ({total_concrete_m3 * 0.12:.2f} m3)",
                    "unit": "m3",
                    "quantity": round(total_concrete_m3 * 0.12, 2),
                    "unit_price_vnd": 850000,
                    "total_amount_vnd": round(total_concrete_m3 * 0.12 * 850000, 0),
                }
            )

        # Check 5: Rebar ratio check (kg per m3)
        if total_concrete_m3 > 5.0 and total_rebar_kg > 0.0:
            rebar_ratio = total_rebar_kg / total_concrete_m3
            if rebar_ratio < 60.0:
                findings.append(
                    {
                        "severity": "warning",
                        "code": "AUDIT-012",
                        "title": f"Tỷ lệ thép/bê tông thấp bất thường ({rebar_ratio:.1f} kg/m3)",
                        "description": f"Hàm lượng thép đạt {rebar_ratio:.1f} kg/m3 bê tông (mức tiêu chuẩn kết cấu thường từ 80 - 160 kg/m3).",
                        "suggestion": "Kiểm tra lại bảng thống kê cốt thép hoặc bổ sung thép dầm/sàn/thành cống.",
                    }
                )
            elif rebar_ratio > 250.0:
                findings.append(
                    {
                        "severity": "info",
                        "code": "AUDIT-013",
                        "title": f"Hàm lượng thép cao ({rebar_ratio:.1f} kg/m3)",
                        "description": f"Hàm lượng thép đạt {rebar_ratio:.1f} kg/m3 bê tông (thường xuất hiện ở đài cọc chịu tải trọng cực lớn).",
                        "suggestion": "Xác nhận đúng thiết kế kỹ thuật.",
                    }
                )

        # Check 6: Excavation vs Backfill
        if total_excavation_m3 > 20.0 and total_backfill_m3 <= 0.0:
            findings.append(
                {
                    "severity": "warning",
                    "code": "AUDIT-014",
                    "title": "Chưa có công tác Đắp đất hoàn trả sau thi công",
                    "description": f"Khối lượng đào đất là {total_excavation_m3:.2f} m3 nhưng chưa có hạng mục đắp đất hoàn trả taluy.",
                    "suggestion": "Bổ sung công tác Đắp đất đầm chặt K=0.90 hoàn trả bờ kênh / hố móng.",
                }
            )
            healed_recommendations.append(
                {
                    "wbs_code": "DAP-SUPPLEMENT",
                    "norm_code": "AL.11110",
                    "item_name": "Đắp đất hoàn trả hố móng/bờ kè đầm chặt K=0.90 (Tự động bổ sung)",
                    "category": "earthwork",
                    "dimension_formula": f"{total_excavation_m3 * 0.70:.2f} m3 (~70% thể tích đào hố móng)",
                    "unit": "m3",
                    "quantity": round(total_excavation_m3 * 0.70, 2),
                    "unit_price_vnd": 45000,
                    "total_amount_vnd": round(total_excavation_m3 * 0.70 * 45000, 0),
                }
            )

        # Check 7: Site safety & temporary drainage works
        if (
            "culvert" in drawing_type
            or "revetment" in drawing_type
            or "hydraulic" in drawing_type
        ) and not has_drainage_pumping:
            findings.append(
                {
                    "severity": "info",
                    "code": "AUDIT-015",
                    "title": "Chưa dự trù biện pháp dẫn dòng & bơm hạ mực nước ngầm",
                    "description": "Công trình thủy lợi / kè kênh mương cần biện pháp đê quai rãnh tiêu và máy bơm hạ nước ngầm phục vụ đổ bê tông.",
                    "suggestion": "Bổ sung gói chi phí đê quai và máy bơm nước thi công.",
                }
            )
            healed_recommendations.append(
                {
                    "wbs_code": "BOM-SUPPLEMENT",
                    "norm_code": "TT.BOM01",
                    "item_name": "Đê quai, rãnh tiêu thoát nước và bơm hạ mực nước ngầm (Tự động bổ sung)",
                    "category": "safety_method",
                    "dimension_formula": "1 gói biện pháp thi công khô ráo đáy móng",
                    "unit": "gói",
                    "quantity": 1.0,
                    "unit_price_vnd": 25000000,
                    "total_amount_vnd": 25000000,
                }
            )

        # PRICE QUALITY GATES (AUDIT-PRC-01 -> AUDIT-PRC-04)
        lean_concrete_price = 0.0
        max_structural_concrete_price = 0.0
        larsen_drive_price_per_m = 0.0
        larsen_extract_price_per_m = 0.0

        for idx, itm in enumerate(items):
            name = str(itm.get("item_name") or "").lower()
            unit = str(itm.get("unit") or "").lower()
            price = float(itm.get("unit_price_vnd") or itm.get("unit_price") or 0.0)

            # Collect concrete prices
            if "bê tông" in name or "bt" in name:
                if "lót" in name or "m100" in name:
                    lean_concrete_price = price
                elif any(
                    m in name
                    for m in [
                        "m200",
                        "m250",
                        "m300",
                        "móng",
                        "tường",
                        "dầm",
                        "sàn",
                        "bản mặt",
                    ]
                ):
                    max_structural_concrete_price = max(
                        max_structural_concrete_price, price
                    )

            # Collect Larsen prices
            if "cừ larsen" in name or "cọc ván thép" in name:
                norm_price_per_m = (price / 100.0) if ("100m" in unit) else price
                if "nhổ" in name:
                    larsen_extract_price_per_m = norm_price_per_m
                elif "đóng" in name or "ép" in name:
                    larsen_drive_price_per_m = norm_price_per_m

            # Gate 2: Formwork Unit & Scale Check
            if "ván khuôn" in name or "van khuon" in name:
                effective_m2_price = (price / 100.0) if ("100m2" in unit) else price
                if 0 < effective_m2_price < 50000:
                    findings.append(
                        {
                            "severity": "critical",
                            "code": "AUDIT-PRC-02",
                            "item_order": idx + 1,
                            "item_name": itm.get("item_name"),
                            "title": f"Đơn giá Ván khuôn quá thấp ({effective_m2_price:,.0f} đ/m2)",
                            "description": f"Công tác '{itm.get('item_name')}' có đơn giá {price:,.0f} đ/{unit} (~{effective_m2_price:,.0f} đ/m2), thấp hơn nhiều so với định mức thực tế (135.000 - 185.000 đ/m2). Có thể bị thiếu số 0 hoặc nhầm lẫn đơn vị tính 100m2.",
                            "suggestion": "Điều chỉnh đơn giá ván khuôn về dải 14.500.000 - 18.500.000 VNĐ / 100m2 (145.000 - 185.000 VNĐ/m2).",
                        }
                    )

            # Gate 3: Handling Cost Ceiling Check
            if ("bốc xếp" in name or "bốc dỡ" in name or "bốc xuống" in name) and (
                "cát" in name or "đá" in name or "sỏi" in name
            ):
                effective_m3_price = (price / 100.0) if ("100m3" in unit) else price
                if effective_m3_price > 35000:
                    findings.append(
                        {
                            "severity": "warning",
                            "code": "AUDIT-PRC-03",
                            "item_order": idx + 1,
                            "item_name": itm.get("item_name"),
                            "title": f"Chi phí Bốc xếp vật liệu rời cao bất thường ({effective_m3_price:,.0f} đ/m3)",
                            "description": f"Công tác '{itm.get('item_name')}' có đơn giá bốc xếp {price:,.0f} đ/{unit}. Bốc xếp cơ giới bằng xúc lật chỉ từ 15.000 - 25.000 đ/m3.",
                            "suggestion": "Điều chỉnh đơn giá bốc xếp cơ giới về mức 18.000 - 25.000 VNĐ/m3.",
                        }
                    )

        # Gate 1: Concrete Grade Hierarchy Check
        if (
            lean_concrete_price > 0
            and max_structural_concrete_price > 0
            and max_structural_concrete_price <= lean_concrete_price
        ):
            findings.append(
                {
                    "severity": "critical",
                    "code": "AUDIT-PRC-01",
                    "title": "Bất hợp lý phân cấp đơn giá Bê tông (M250 <= M100)",
                    "description": f"Bê tông kết cấu ({max_structural_concrete_price:,.0f} đ/m3) đang có đơn giá thấp hơn hoặc bằng Bê tông lót M100 ({lean_concrete_price:,.0f} đ/m3). Bê tông M250 có cấp phối xi măng cao hơn và dùng đá 1x2, bắt buộc phải có đơn giá cao hơn M100.",
                    "suggestion": "Áp dụng định mức: Bê tông lót M100 ~ 850.000 - 950.000 đ/m3; Bê tông kết cấu M250 ~ 1.450.000 - 1.550.000 đ/m3.",
                }
            )

        # Gate 4: Larsen Driving vs Extraction Check
        if (
            larsen_drive_price_per_m > 0
            and larsen_extract_price_per_m > larsen_drive_price_per_m
        ):
            findings.append(
                {
                    "severity": "warning",
                    "code": "AUDIT-PRC-04",
                    "title": f"Đơn giá Nhổ cừ Larsen ({larsen_extract_price_per_m:,.0f} đ/m) cao hơn Đóng cừ ({larsen_drive_price_per_m:,.0f} đ/m)",
                    "description": "Trong thi công búa rung thông thường, công tác nhổ cừ nhanh hơn và chi phí định mức chỉ bằng 60% - 85% chi phí đóng cừ.",
                    "suggestion": f"Điều chỉnh đơn giá nhổ cừ về khoảng 30.000 - 40.000 VNĐ/m (<= {larsen_drive_price_per_m * 0.85:,.0f} VNĐ/m).",
                }
            )

        # Calculate Quality Score (100 - penalties)
        crit_count = sum(1 for f in findings if f["severity"] == "critical")
        warn_count = sum(1 for f in findings if f["severity"] == "warning")
        info_count = sum(1 for f in findings if f["severity"] == "info")

        penalty = (crit_count * 20) + (warn_count * 8) + (info_count * 2)
        quality_score = max(30, min(100, 100 - penalty))

        grade = (
            "XUẤT SẮC (A+)"
            if quality_score >= 95
            else (
                "ĐẠT CHUẨN (A)"
                if quality_score >= 85
                else (
                    "CẦN HIỆU CHỈNH (B)"
                    if quality_score >= 70
                    else "CẢNH BÁO RỦI RO (C)"
                )
            )
        )

        return {
            "status": "success",
            "takeoff_title": takeoff_title,
            "quality_score": quality_score,
            "grade": grade,
            "total_items_audited": len(items),
            "findings_count": len(findings),
            "critical_count": crit_count,
            "warning_count": warn_count,
            "info_count": info_count,
            "metrics": {
                "total_concrete_m3": round(total_concrete_m3, 2),
                "total_formwork_m2": round(total_formwork_m2, 2),
                "total_rebar_kg": round(total_rebar_kg, 2),
                "total_rebar_tons": round(total_rebar_kg / 1000.0, 3),
                "rebar_ratio_kg_per_m3": round(total_rebar_kg / total_concrete_m3, 1)
                if total_concrete_m3 > 0
                else 0.0,
                "formwork_ratio_m2_per_m3": round(
                    total_formwork_m2 / total_concrete_m3, 2
                )
                if total_concrete_m3 > 0
                else 0.0,
                "total_excavation_m3": round(total_excavation_m3, 2),
                "total_backfill_m3": round(total_backfill_m3, 2),
            },
            "findings": findings,
            "recommended_supplements": healed_recommendations,
        }
