#!/usr/bin/env python3
"""Validate the normalized CSV truth sources and user-facing workbook structure."""

from __future__ import annotations

import argparse
import csv
import json
import zipfile
from collections import Counter
from pathlib import Path
from xml.etree import ElementTree as ET


ROOT = Path(__file__).resolve().parents[1]
VALID_STATUSES = {"有", "部分具备", "暂无", "待核实", "不适用"}
EXPECTED_DOMAINS = {"前厅", "后厨", "食安", "营养健康", "经营管理", "平台与集成", "交付运维", "智能硬件"}
EXPECTED_SHEETS = [
    "说明与统计", "功能明细", "竞品矩阵", "前厅", "后厨", "食安", "营养健康",
    "经营管理", "平台集成", "交付运维", "智能硬件", "证据台账", "待补证清单",
]


def read_rows(path: Path) -> tuple[list[str], list[dict[str, str]]]:
    with path.open(encoding="utf-8-sig", newline="") as handle:
        reader = csv.DictReader(handle)
        return list(reader.fieldnames or []), list(reader)


def workbook_sheet_names(path: Path) -> tuple[list[str], int]:
    ns = {"m": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
    with zipfile.ZipFile(path) as archive:
        workbook = ET.fromstring(archive.read("xl/workbook.xml"))
        names = [node.attrib["name"] for node in workbook.findall("m:sheets/m:sheet", ns)]
        formula_count = 0
        for name in archive.namelist():
            if name.startswith("xl/worksheets/sheet") and name.endswith(".xml"):
                formula_count += len(ET.fromstring(archive.read(name)).findall(".//m:f", ns))
    return names, formula_count


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--workbook", type=Path, required=True)
    parser.add_argument("--report", type=Path)
    args = parser.parse_args()

    catalog_headers, catalog = read_rows(ROOT / "capability-catalog.csv")
    matrix_headers, matrix = read_rows(ROOT / "competitor-matrix.csv")
    evidence_headers, evidence = read_rows(ROOT / "evidence-ledger.csv")
    backlog_headers, backlog = read_rows(ROOT / "validation-backlog.csv")
    failures: list[str] = []

    ids = [row["capability_id"] for row in catalog]
    if len(ids) != len(set(ids)):
        failures.append("capability_id is not unique")
    if len(catalog) != len(matrix):
        failures.append("catalog and matrix row counts differ")
    if {row["业务域"] for row in catalog} != EXPECTED_DOMAINS:
        failures.append("domain set differs from expected eight domains")
    if {row["标准版优先级"] for row in catalog} - {"P0", "P1"}:
        failures.append("unexpected priority value")

    competitors = matrix_headers[7:-1]
    invalid_statuses = Counter()
    for row in matrix:
        for competitor in competitors:
            if row[competitor] not in VALID_STATUSES:
                invalid_statuses[row[competitor]] += 1
    if invalid_statuses:
        failures.append(f"invalid matrix statuses: {dict(invalid_statuses)}")
    if any(row["当前状态"] != "待核实" for row in backlog):
        failures.append("validation backlog contains non-pending status")
    if any(row["capability_id"] and row["capability_id"] not in set(ids) for row in evidence):
        failures.append("evidence contains unknown capability_id")

    sheet_names, formula_count = workbook_sheet_names(args.workbook)
    if sheet_names != EXPECTED_SHEETS:
        failures.append(f"unexpected workbook sheets: {sheet_names}")
    if formula_count != 97:
        failures.append(f"unexpected formula count: {formula_count}")

    report = {
        "status": "PASS" if not failures else "FAIL",
        "workbook": str(args.workbook),
        "catalog_rows": len(catalog),
        "matrix_rows": len(matrix),
        "competitors": competitors,
        "domain_counts": dict(Counter(row["业务域"] for row in catalog)),
        "priority_counts": dict(Counter(row["标准版优先级"] for row in catalog)),
        "evidence_rows": len(evidence),
        "validation_backlog_rows": len(backlog),
        "sheet_names": sheet_names,
        "formula_count": formula_count,
        "failures": failures,
        "headers": {
            "catalog": catalog_headers,
            "matrix": matrix_headers,
            "evidence": evidence_headers,
            "backlog": backlog_headers,
        },
    }
    rendered = json.dumps(report, ensure_ascii=False, indent=2)
    if args.report:
        args.report.parent.mkdir(parents=True, exist_ok=True)
        args.report.write_text(rendered + "\n", encoding="utf-8")
    print(rendered)
    raise SystemExit(1 if failures else 0)


if __name__ == "__main__":
    main()
