import io

import openpyxl
import pytest

from app.modules.takeoff.application.boq_audit_engine import BoqAuditEngine
from app.modules.takeoff.application.boq_statutory_cost_service import (
    StatutoryCostSummaryEngine,
)
from app.modules.takeoff.application.excel_exporter import export_takeoff_to_excel


@pytest.fixture
def sample_boq_items():
    return [
        {
            "id": "item-1",
            "item_name": "Đào móng đất cấp III bằng máy",
            "category": "earthwork",
            "unit": "m3",
            "quantity": 100.0,
            "unit_price_vnd": 45000.0,
            "total_amount_vnd": 4500000.0,
            "material_cost_vnd": 0.0,
            "labor_cost_vnd": 10000.0,
            "equipment_cost_vnd": 35000.0,
            "norm_code": "AB.11311",
        },
        {
            "id": "item-2",
            "item_name": "Bê tông móng M250 đá 1x2",
            "category": "concrete",
            "unit": "m3",
            "quantity": 50.0,
            "unit_price_vnd": 1250000.0,
            "total_amount_vnd": 62500000.0,
            "material_cost_vnd": 900000.0,
            "labor_cost_vnd": 210000.0,
            "equipment_cost_vnd": 140000.0,
            "norm_code": "AF.11210",
        },
        {
            "id": "item-3",
            "item_name": "Cốt thép móng CB400 D<=18",
            "category": "rebar",
            "unit": "tấn",
            "quantity": 6.0,
            "unit_price_vnd": 18500000.0,
            "total_amount_vnd": 111000000.0,
            "material_cost_vnd": 15500000.0,
            "labor_cost_vnd": 2500000.0,
            "equipment_cost_vnd": 500000.0,
            "norm_code": "AF.61121",
        },
    ]


def test_statutory_cost_summary_calculation(sample_boq_items):
    summary = StatutoryCostSummaryEngine.calculate_statutory_summary(
        items=sample_boq_items,
        drawing_type="civil_building",
        vat_rate=8.0,
        include_contingency=True,
    )

    assert summary["status"] == "success"
    assert (
        summary["legal_basis"] == "Nghị định 206/2026/NĐ-CP & Thông tư 38/2026/TT-BXD"
    )
    assert summary["total_direct_t"] == 178000000.0  # 4.5M + 62.5M + 111M

    # Direct cost components
    assert summary["table_rows"][0]["code"] == "T"
    assert summary["table_rows"][0]["amount_vnd"] == 178000000.0

    # Indirect cost (Civil: 7.3% C + 1.2% Tam + 2.5% TT = 11.0%)
    c_overhead = round(178000000.0 * 0.073, 0)
    t_tam = round(178000000.0 * 0.012, 0)
    tt = round(178000000.0 * 0.025, 0)
    expected_gt = c_overhead + t_tam + tt
    assert summary["total_indirect_gt"] == expected_gt

    # Statutory Profit (5.5% of T + GT)
    expected_tl = round((178000000.0 + expected_gt) * 0.055, 0)
    assert summary["statutory_profit_tl"] == expected_tl

    # Before tax G = T + GT + TL
    expected_g = 178000000.0 + expected_gt + expected_tl
    assert summary["cost_before_tax_g"] == expected_g

    # VAT 8%
    expected_vat = round(expected_g * 0.08, 0)
    assert summary["vat_amount"] == expected_vat

    # Grand total should be greater than after tax
    assert summary["grand_total_budget"] > summary["cost_after_tax_gxd"]


def test_statutory_cost_coefficients_by_project_type():
    coeff_civil = StatutoryCostSummaryEngine.get_coefficients("civil_building")
    assert coeff_civil["k_C"] == 7.3

    coeff_hydraulic = StatutoryCostSummaryEngine.get_coefficients("culvert_revetment")
    assert coeff_hydraulic["k_C"] == 5.5

    coeff_transport = StatutoryCostSummaryEngine.get_coefficients("transport_road")
    assert coeff_transport["k_C"] == 6.2


def test_boq_audit_engine_detection(sample_boq_items):
    # sample_boq_items has 50m3 concrete but 0m2 formwork, 100m3 excavation but 0 backfill
    audit_res = BoqAuditEngine.audit_takeoff(
        items=sample_boq_items,
        drawing_type="civil_building",
        takeoff_title="Test Drawing Takeoff",
    )

    assert audit_res["status"] == "success"
    assert (
        audit_res["quality_score"] < 100
    )  # Penalized because formwork & lean concrete are missing
    assert len(audit_res["findings"]) > 0

    codes = [f["code"] for f in audit_res["findings"]]
    # Should detect missing formwork (AUDIT-010)
    assert "AUDIT-010" in codes
    # Should detect missing lean concrete (AUDIT-011)
    assert "AUDIT-011" in codes
    # Should detect missing backfill (AUDIT-014)
    assert "AUDIT-014" in codes

    # Should provide recommended supplements for 1-Click healing
    assert len(audit_res["recommended_supplements"]) >= 2
    supplement_names = [s["item_name"] for s in audit_res["recommended_supplements"]]
    assert any("Ván khuôn" in name for name in supplement_names)
    assert any("Bê tông lót" in name for name in supplement_names)


def test_excel_export_4_sheets(sample_boq_items):
    takeoff = {
        "id": "test-tk-1",
        "drawing_name": "DWG-TEST.pdf",
        "project_name": "Công trình Nhà văn hóa thí nghiệm",
        "drawing_type": "civil_building",
    }

    excel_bytes = export_takeoff_to_excel(takeoff=takeoff, items=sample_boq_items)
    assert len(excel_bytes) > 0

    # Load workbook from memory
    wb = openpyxl.load_workbook(io.BytesIO(excel_bytes))
    sheet_names = wb.sheetnames

    assert len(sheet_names) == 4
    assert "1. TH Kinh Phí (NĐ 206)" in sheet_names
    assert "2. BoQ Khối Lượng" in sheet_names
    assert "3. Đơn Giá Chi Tiết (VL+NC+M)" in sheet_names
    assert "4. Tổng Hợp Vật Tư (MR)" in sheet_names

    # Check Sheet 1 header and content
    ws1 = wb["1. TH Kinh Phí (NĐ 206)"]
    assert "CÔNG TY TNHH XÂY DỰNG ĐỊNH SƠN" in str(ws1["A1"].value)
    assert "CHI PHÍ TRỰC TIẾP" in str(ws1["C8"].value)

    # Check Sheet 4 material items
    ws4 = wb["4. Tổng Hợp Vật Tư (MR)"]
    assert "BẢNG TỔNG HỢP NHU CẦU VẬT TƯ" in str(ws4["A2"].value)
