#!/usr/bin/env python3
"""Build the local EVT review pack; exports are explicitly not manufacturing release."""
from __future__ import annotations

import hashlib
import json
import shutil
import zipfile
from pathlib import Path

PROJECT = Path(__file__).resolve().parents[3]
LAMP = Path(__file__).resolve().parent
AUDIT = PROJECT / "outputs/三款PCBA候选状态审计-A14-v0.1-2026-10-10"
OUT = PROJECT / "outputs/AI灯LMR51450电源EVT评审包-A1-2026-10-10"


def sha(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()


def refresh_manifest(root: Path, filename: str) -> None:
    target = root / filename
    rows = []
    for path in sorted(root.rglob("*")):
        if not path.is_file() or path == target or path.name.endswith(".kicad_prl") or path.name.startswith("."):
            continue
        rows.append(f"{sha(path)}  {path.relative_to(root).as_posix()}")
    target.write_text("\n".join(rows) + "\n")


def main() -> None:
    refresh_manifest(LAMP, "MANIFEST-SHA256.txt")
    refresh_manifest(AUDIT, "SHA256SUMS.txt")
    files = {
        "00-工程说明.md": LAMP / "README.md",
        "KiCad/lamp_buck_lmr51450_a1.kicad_sch": LAMP / "lamp_buck_lmr51450_a1.kicad_sch",
        "KiCad/lamp_buck_lmr51450_a1.kicad_pcb": LAMP / "lamp_buck_lmr51450_a1.kicad_pcb",
        "KiCad/lamp_buck_lmr51450_a1.kicad_pro": LAMP / "lamp_buck_lmr51450_a1.kicad_pro",
        "KiCad/lamp_buck_lmr51450_a1.net.xml": LAMP / "lamp_buck_lmr51450_a1.net.xml",
        "KiCad/fp-lib-table": LAMP / "fp-lib-table",
        "KiCad/sym-lib-table": LAMP / "sym-lib-table",
        "KiCad/Project.kicad_sym": LAMP / "Project.kicad_sym",
        "KiCad/Lamp_Power.pretty/LMR51450_WSON_DRR0012.kicad_mod": LAMP / "Lamp_Power.pretty/LMR51450_WSON_DRR0012.kicad_mod",
        "KiCad/Lamp_Power.pretty/TPS22992SRXN_WQFN-HR-8_1.25x1.25mm_P0.4mm.kicad_mod": LAMP / "Lamp_Power.pretty/TPS22992SRXN_WQFN-HR-8_1.25x1.25mm_P0.4mm.kicad_mod",
        "Tools/verify_lmr51450_pcb.py": LAMP / "verify_lmr51450_pcb.py",
        "Tools/package_lamp_review_pack.py": LAMP / "package_lamp_review_pack.py",
        "Validation/verification.json": LAMP / "verification.json",
        "Validation/pcb-net-parity.json": LAMP / "pcb-net-parity.json",
        "Validation/pcb-build.json": LAMP / "pcb-build.json",
        "Validation/lmr51450_final_erc.rpt": LAMP / "lmr51450_final_erc.rpt",
        "Validation/lmr51450_refined_drc.rpt": LAMP / "lmr51450_refined_drc.rpt",
        "Validation/lmr51450_cli_schematic_parity.rpt": LAMP / "lmr51450_cli_schematic_parity.rpt",
        "Validation/lmr51450-final-stats.json": LAMP / "lmr51450-final-stats.json",
        "Validation/MANIFEST-SHA256.txt": LAMP / "MANIFEST-SHA256.txt",
        "Cost/BOM-delta-1000pcs.csv": LAMP / "BOM-delta-1000pcs.csv",
        "Cost/COST-QUOTE-INPUT-1000PCS.csv": LAMP / "COST-QUOTE-INPUT-1000PCS.csv",
        "Cost/power-budget-screen.csv": LAMP / "power-budget-screen.csv",
        "Test/EVT-BENCH-TEST-MATRIX.csv": LAMP / "EVT-BENCH-TEST-MATRIX.csv",
        "CAM-PREVIEW-HOLD/README.md": LAMP / "CAM-PREVIEW-HOLD/README.md",
        "CAM-PREVIEW-HOLD/positions-front.csv": LAMP / "CAM-PREVIEW-HOLD/positions-front.csv",
        "三款状态审计/01-三款候选状态.csv": AUDIT / "01-三款候选状态.csv",
        "三款状态审计/02-千台成本边界.csv": AUDIT / "02-千台成本边界.csv",
    }
    for directory in ("gerbers", "drill"):
        for path in sorted((LAMP / "CAM-PREVIEW-HOLD" / directory).glob("*")):
            files[f"CAM-PREVIEW-HOLD/{directory}/{path.name}"] = path
    OUT.mkdir(parents=True, exist_ok=True)
    for relative, source in files.items():
        destination = OUT / relative
        destination.parent.mkdir(parents=True, exist_ok=True)
        shutil.copy2(source, destination)
    refresh_manifest(OUT, "PACKAGE-MANIFEST-SHA256.txt")
    archive = OUT.with_suffix(".zip")
    if archive.exists():
        archive.unlink()
    with zipfile.ZipFile(archive, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=6) as handle:
        for path in sorted(OUT.rglob("*")):
            if path.is_file():
                handle.write(path, Path(OUT.name) / path.relative_to(OUT))
    with zipfile.ZipFile(archive) as handle:
        bad_member = handle.testzip()
        if bad_member:
            raise RuntimeError(f"ZIP integrity failure: {bad_member}")
    digest = sha(archive)
    archive.with_suffix(archive.suffix + ".sha256").write_text(f"{digest}  {archive.name}\n")
    state_path = PROJECT / "work/tri-product-continuation-2026-10-10.nosync/工程状态增量-2026-10-10-continuation.json"
    state = json.loads(state_path.read_text())
    state["lamp_evt_review_package"] = {
        "directory": OUT.relative_to(PROJECT).as_posix(),
        "zip": archive.relative_to(PROJECT).as_posix(),
        "zip_sha256": digest,
        "zip_bytes": archive.stat().st_size,
        "file_count": sum(1 for path in OUT.rglob("*") if path.is_file()),
        "manufacturing_release": False,
    }
    state_path.write_text(json.dumps(state, ensure_ascii=False, indent=2) + "\n")
    print(json.dumps({"zip": str(archive), "sha256": digest, "bytes": archive.stat().st_size, "zip_test": "PASS"}, ensure_ascii=False))


if __name__ == "__main__":
    main()
