#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
from pathlib import Path


REQUIRED = {
    "sequence", "spu_sequence", "sku_sequence", "release_code", "release_name",
    "spu", "sku", "name", "buyer", "one_liner", "primary_buying_point",
    "suitable_for", "standard_combo", "core_modules", "main_flow",
    "customer_values", "boundaries", "forbidden_terms", "infographic_focus",
    "representative_projects", "deployment", "entry_points", "options", "evidence_status",
}


def main() -> int:
    parser = argparse.ArgumentParser(description="Audit a smart-canteen SKU manifest portfolio.")
    parser.add_argument("--manifests", required=True, type=Path)
    parser.add_argument("--expected-count", required=True, type=int)
    parser.add_argument("--report", type=Path)
    args = parser.parse_args()

    errors: list[str] = []
    warnings: list[str] = []
    items: list[dict] = []
    codes: set[str] = set()
    sequences: set[str] = set()
    release_codes: set[str] = set()
    for path in sorted(args.manifests.glob("*.json")):
        data = json.loads(path.read_text(encoding="utf-8"))
        sku = data.get("sku", path.stem)
        missing = sorted(REQUIRED - set(data))
        if missing:
            errors.append(f"{sku}: missing fields {missing}")
        if sku in codes:
            errors.append(f"duplicate SKU code: {sku}")
        codes.add(sku)
        sequence = data.get("sequence", "")
        if sequence in sequences:
            errors.append(f"duplicate sequence: {sequence}")
        sequences.add(sequence)
        release_code = data.get("release_code", "")
        if release_code in release_codes:
            errors.append(f"duplicate release_code: {release_code}")
        release_codes.add(release_code)
        expected_release_name = f"{release_code}-{data.get('name', '')}"
        if sku != release_code:
            errors.append(f"{sku}: public sku must equal release_code {release_code}")
        if data.get("release_name") != expected_release_name:
            errors.append(f"{sku}: release_name mismatch: {data.get('release_name')} != {expected_release_name}")
        if len(data.get("core_modules", [])) != 4:
            errors.append(f"{sku}: core_modules must equal 4")
        if not 4 <= len(data.get("main_flow", [])) <= 6:
            errors.append(f"{sku}: main_flow must contain 4-6 steps")
        if len(data.get("customer_values", [])) != 3:
            errors.append(f"{sku}: customer_values must equal 3")
        if len(data.get("boundaries", [])) != 3:
            errors.append(f"{sku}: boundaries must equal 3")
        flow = "\n".join(data.get("main_flow", []))
        for forbidden in data.get("forbidden_terms", []):
            if forbidden and forbidden in flow:
                errors.append(f"{sku}: forbidden term in main flow: {forbidden}")
        if "待" in data.get("evidence_status", ""):
            warnings.append(f"{sku}: {data['evidence_status']}")
        items.append({
            "sequence": sequence,
            "release_code": release_code,
            "release_name": data.get("release_name"),
            "sku": sku,
            "name": data.get("name"),
            "spu": data.get("spu"),
            "evidence_status": data.get("evidence_status"),
        })

    count = len(items)
    if count != args.expected_count:
        errors.append(f"portfolio count mismatch: expected {args.expected_count}, found {count}")
    expected_sequences = {f"{index:02d}" for index in range(1, count + 1)}
    if sequences != expected_sequences:
        errors.append(f"portfolio sequence mismatch: expected {sorted(expected_sequences)}, found {sorted(sequences)}")
    items.sort(key=lambda item: item["sequence"])
    report = {
        "status": "PASS" if not errors else "BLOCKED",
        "expected_count": args.expected_count,
        "actual_count": count,
        "items": items,
        "warnings": warnings,
        "errors": errors,
    }
    raw = json.dumps(report, ensure_ascii=False, indent=2) + "\n"
    if args.report:
        args.report.parent.mkdir(parents=True, exist_ok=True)
        args.report.write_text(raw, encoding="utf-8")
    print(raw, end="")
    return 0 if not errors else 2


if __name__ == "__main__":
    raise SystemExit(main())
