"""DAMA数据治理规则检查（财务七规则）测试 — 2026-08-30

覆盖 data_quality.py 的 _run_governance_checks（governance-check 端点核心逻辑）：
7条规则：unit_check/dup_alert/orphan_check/virtual_pollution/entity_check/kpi_completeness/reconciliation
+ 评分规则（error 扣 min(15,count*3)，warning 扣 min(10,count*1)，规则4 manual 附加扣）

验收活数据对照（生产环境实测）：reconciliation=3、kpi_completeness=53、其余0。
"""

import json
from datetime import datetime

import pytest

from app.models import (
    KPIDefinition, KPIValue, KPIAlert, CashPlan, BudgetPlan,
)
from app.api.data_quality import _run_governance_checks


def _mk_kpi(db, **kw):
    defaults = {
        "entity_id": 1, "kpi_code": "TEST_001", "kpi_name": "测试KPI",
        "status": "active", "target_value": 100.0, "target_yearly": 100.0,
        "formula": "x", "data_source": "test", "data_owner": "财务部",
        "unit": "元", "kpi_level": "operational",
    }
    defaults.update(kw)
    k = KPIDefinition(**defaults)
    db.add(k)
    db.commit()
    db.refresh(k)
    return k


def _mk_plan(db, **kw):
    defaults = {
        "entity_id": 1, "plan_type": "receive", "amount": 10.0,
        "plan_date": datetime(2026, 8, 1), "source": "manual", "status": "pending",
    }
    defaults.update(kw)
    p = CashPlan(**defaults)
    db.add(p)
    db.commit()
    db.refresh(p)
    return p


def _mk_alert(db, kpi_id, plan_id, **kw):
    defaults = {
        "kpi_id": kpi_id, "alert_type": "cash_plan", "status": "pending",
        "alert_message": "应收预警",
        "suggestion": json.dumps({"plan_id": plan_id}),
    }
    defaults.update(kw)
    a = KPIAlert(**defaults)
    db.add(a)
    db.commit()
    db.refresh(a)
    return a


class TestGovernanceSevenRules:
    def test_clean_db_all_pass(self, db):
        """空库：7条规则全部通过，score=100"""
        r = _run_governance_checks(db, 0)
        assert r["total_rules"] == 7
        assert r["score"] == 100
        assert r["total_deduct"] == 0
        assert len(r["passed"]) == 7
        for item in r["issues"]:
            assert item["count"] == 0

    def test_all_rules_hit(self, db):
        """构造数据触发全部7条规则"""
        # KPI-1: active + 有值 + 年度目标100 但预算月度合计200（勾稽差异100%）
        k1 = _mk_kpi(db, kpi_code="KPI_001", kpi_name="勾稽KPI", target_yearly=100.0)
        db.add(KPIValue(kpi_id=k1.id, entity_id=1, period="2026-06", actual_value=50.0))
        for m in range(1, 13):
            db.add(BudgetPlan(kpi_id=k1.id, entity_id=1, period=f"2026-{m:02d}",
                              budget_value=200.0 / 12, budget_year=2026, budget_month=m,
                              version="v1.0", status="active"))
        db.commit()

        # KPI-2: active 无任何值（KPI完整性命中）
        _mk_kpi(db, kpi_code="KPI_002", kpi_name="无值KPI", target_yearly=10.0)

        # KPI-3: 值实体=2 ≠ 定义实体=1（实体归属命中）
        k3 = _mk_kpi(db, kpi_code="KPI_003", kpi_name="实体错乱KPI", target_yearly=10.0)
        db.add(KPIValue(kpi_id=k3.id, entity_id=2, period="2026-06", actual_value=5.0))
        db.commit()

        # 单位校验：amount=50000 > 10000（单位错乱命中）
        _mk_plan(db, id=1, amount=50000.0)

        # 虚拟污染：source=test_import（error）+ source=manual（待人工确认）
        _mk_plan(db, id=2, amount=100.0, source="test_import")
        _mk_plan(db, id=3, amount=100.0, source="manual")

        # 孤儿预警：plan_id=999 不存在（孤儿命中）
        _mk_alert(db, k1.id, 999)

        # 重复预警：plan_id=5 两条 pending（重复命中）
        _mk_plan(db, id=5, amount=100.0)
        _mk_alert(db, k1.id, 5)
        _mk_alert(db, k1.id, 5)

        r = _run_governance_checks(db, 0)
        by_rule = {i["rule"]: i for i in r["issues"]}

        assert by_rule["unit_check"]["count"] == 1
        assert by_rule["dup_alert"]["count"] == 1
        assert by_rule["orphan_check"]["count"] == 1
        assert by_rule["virtual_pollution"]["count"] == 1
        assert by_rule["virtual_pollution"]["manual_count"] == 3  # plan#1/#3/#5 默认manual
        assert by_rule["entity_check"]["count"] == 1
        assert by_rule["kpi_completeness"]["count"] == 1
        assert by_rule["reconciliation"]["count"] == 1

        # 评分：5条error × min(15,3)=3 → 15；2条warning × 1 → 2；manual附加 min(10,3)=3 → 总扣20
        assert r["total_deduct"] == 20
        assert r["score"] == 80
        assert len(r["passed"]) == 0

    def test_entity_scoped(self, db):
        """entity_id 限定：只检查该实体数据"""
        k1 = _mk_kpi(db, kpi_code="KPI_001", kpi_name="实体1KPI", entity_id=1, target_yearly=10.0)
        k2 = _mk_kpi(db, kpi_code="KPI_002", kpi_name="实体2KPI", entity_id=2, target_yearly=10.0)
        db.add(KPIValue(kpi_id=k2.id, entity_id=2, period="2026-06", actual_value=5.0))
        db.commit()

        r1 = _run_governance_checks(db, 1)
        comp1 = {i["rule"]: i["count"] for i in r1["issues"]}
        assert comp1["kpi_completeness"] == 1  # 实体1下KPI_001无值
        assert comp1["entity_check"] == 0      # 实体1下无实体错乱

        r2 = _run_governance_checks(db, 2)
        comp2 = {i["rule"]: i["count"] for i in r2["issues"]}
        assert comp2["kpi_completeness"] == 0  # KPI_002有值
        assert comp2["entity_check"] == 0      # 值实体=2与定义实体=2一致
        assert comp2["reconciliation"] == 0    # 无预算行不参与勾稽
