#!/usr/bin/env python3

import tempfile
import unittest
from pathlib import Path

import validate_mlps_materials as validator


def intake_row(field_id: str, value: str = "已核实值", **overrides: str) -> dict[str, str]:
    row = {
        "field_id": field_id,
        "section": "测试",
        "field_name": field_id,
        "applicable_level": "common",
        "requirement": "required",
        "value": value,
        "status": "confirmed",
        "evidence_level": "A",
        "evidence_source": "test-evidence",
        "owner": "测试负责人",
        "confidentiality": "内部",
        "consistency_key": "",
        "notes": "",
    }
    row.update(overrides)
    return row


def complete_intake(level: str) -> list[dict[str, str]]:
    ids = validator.REQUIRED_FIELD_IDS | (validator.LEVEL3_REQUIRED_FIELD_IDS if level == "3" else set())
    rows = [intake_row(field_id) for field_id in sorted(ids)]
    for row in rows:
        if row["field_id"] == "base.level":
            row["value"] = level
    for field_id in ("base.system_name", "report.system_name", "filing.system_name"):
        row = next(item for item in rows if item["field_id"] == field_id)
        row["value"] = "测试信息系统"
        row["consistency_key"] = "system_name"
    return rows


class ValidatorTests(unittest.TestCase):
    def test_complete_level2_intake_has_no_issues(self) -> None:
        issues: list[dict[str, str]] = []
        validator.validate_intake(complete_intake("2"), "2", issues)
        self.assertEqual([], issues)

    def test_detects_name_conflict_in_level2(self) -> None:
        rows = complete_intake("2")
        next(row for row in rows if row["field_id"] == "filing.system_name")["value"] = "另一个系统"
        issues: list[dict[str, str]] = []
        validator.validate_intake(rows, "2", issues)
        self.assertIn("CONSISTENCY_CONFLICT", {item["rule"] for item in issues})

    def test_detects_inference_and_secret(self) -> None:
        rows = complete_intake("2")
        target = next(row for row in rows if row["field_id"] == "scope.identity")
        target["evidence_level"] = "D"
        target["notes"] = "password=<REDACTED>"
        issues: list[dict[str, str]] = []
        validator.validate_intake(rows, "2", issues)
        rules = {item["rule"] for item in issues}
        self.assertIn("CONFIRMED_BY_INFERENCE", rules)
        self.assertIn("SENSITIVE_VALUE", rules)

    def test_restricted_mobile_is_warning_not_blocker(self) -> None:
        rows = complete_intake("2")
        target = next(row for row in rows if row["field_id"] == "security.incident")
        target["value"] = "应急联系人 13812345678"
        target["confidentiality"] = "受限"
        issues: list[dict[str, str]] = []
        validator.validate_intake(rows, "2", issues)
        matches = [item for item in issues if item["rule"] == "SENSITIVE_VALUE"]
        self.assertEqual(["MEDIUM"], [item["severity"] for item in matches])

    def test_level3_requires_extra_rows(self) -> None:
        issues: list[dict[str, str]] = []
        validator.validate_intake(complete_intake("2"), "3", issues)
        missing = {item["item_id"] for item in issues if item["rule"] == "MISSING_TEMPLATE_ROW"}
        self.assertEqual(validator.LEVEL3_REQUIRED_FIELD_IDS, missing)

    def test_complete_required_materials_exist(self) -> None:
        with tempfile.TemporaryDirectory() as directory:
            base_dir = Path(directory)
            ids = validator.REQUIRED_MATERIAL_IDS | validator.LEVEL3_REQUIRED_MATERIAL_IDS
            rows = []
            for material_id in sorted(ids):
                path = base_dir / f"{material_id}.txt"
                path.write_text("test", encoding="utf-8")
                rows.append({
                    "material_id": material_id,
                    "material_name": material_id,
                    "applicable_level": "3" if material_id in validator.LEVEL3_REQUIRED_MATERIAL_IDS else "common",
                    "requirement": "required",
                    "status": "confirmed",
                    "file_path": path.name,
                    "issuer_or_owner": "测试负责人",
                    "seal_required": "conditional",
                    "review_required": "yes",
                    "source_basis": "test",
                    "notes": "",
                })
            issues: list[dict[str, str]] = []
            validator.validate_materials(rows, "3", base_dir, issues)
            self.assertEqual([], issues)


if __name__ == "__main__":
    unittest.main()
