#!/usr/bin/env python3
"""Independent verification for the 2026-10-31 wizardwork census artifact.

RE-APPROACH: this checker does NOT import the extractor. It re-derives the
expected figures from `git ls-tree -r -l <recording HEAD>` scoped to
`wizard-work/`, where <recording HEAD> is the commit SHA recorded inside the
committed JSON artifact. That makes the check stable even though the repo's
HEAD keeps moving (autonomous dispatch commits every 5 minutes under cron).

Re-derived figures: per-lane file counts, total file count, total bytes, and the
flat manifest (relative paths of every committed blob in the recording commit).

The committed CSV/JSON/MD artifacts are the record under test; exit code is the
verdict: 0 = correct, 1 = a check failed.

Run: cd wizard-work/ledger && python3 2026-10-31-wizardwork-census/CHECK
"""

import csv
import json
import os
import subprocess
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
REPO = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
SCOPE = "wizard-work/"
DAY = "2026-10-31"
CSV_NAME = "%s-wizardwork-census.csv" % DAY
JSON_NAME = "%s-wizardwork-census.json" % DAY
MD_NAME = "%s-wizardwork-census.md" % DAY

failures = []


def check(name, cond, detail=""):
    print(("%s %s" % ("PASS" if cond else "FAIL", name))
          + ("" if cond else " " + repr(detail)))
    if not cond:
        failures.append(name)


def run_git(*args):
    return subprocess.check_output(["git"] + list(args), cwd=REPO, text=True)


def main():
    # --- read the committed artifact under test ------------------------------
    json_path = os.path.join(HERE, JSON_NAME)
    with open(json_path, encoding="utf-8") as fh:
        js = json.load(fh)
    head_sha = js["summary"]["head_sha"]

    # recording HEAD must resolve to a real commit in this repo
    try:
        resolved = run_git("rev-parse", "--verify", "--quiet", head_sha + "^{commit}").strip()
    except subprocess.CalledProcessError:
        resolved = ""
    check("recorded head_sha resolves to a commit",
          resolved == head_sha, "json=%r resolved=%r" % (head_sha, resolved))

    # --- independent re-derivation from the RECORDED commit ------------------
    tree = run_git("ls-tree", "-r", "-l", head_sha)
    expected_lanes = {}
    expected_files = 0
    expected_bytes = 0
    expected_manifest = []
    for line in tree.strip().splitlines():
        parts = line.split()
        _mode, otype, _obj, size_s, path = parts
        if otype != "blob" or not path.startswith(SCOPE):
            continue
        rel = path[len(SCOPE):]
        lane = rel.split("/", 1)[0]
        expected_lanes.setdefault(lane, [0, 0])
        expected_lanes[lane][0] += 1
        expected_lanes[lane][1] += int(size_s)
        expected_manifest.append({"rel_path": rel, "size_bytes": int(size_s)})
        expected_files += 1
        expected_bytes += int(size_s)

    # --- committed CSV -------------------------------------------------------
    csv_path = os.path.join(HERE, CSV_NAME)
    with open(csv_path, encoding="utf-8", newline="") as fh:
        rows = list(csv.reader(fh))
    csv_header, committed = rows[0], rows[1:]
    check("csv header",
          csv_header == ["rel_path", "size_bytes", "head_sha"], repr(csv_header))
    check("csv row count == git-rederived files",
          len(committed) == expected_files,
          "committed=%d expected=%d" % (len(committed), expected_files))
    csv_bytes = sum(int(r[1]) for r in committed if len(r) >= 2)
    check("csv total bytes == git-rederived bytes",
          csv_bytes == expected_bytes,
          "committed=%d expected=%d" % (csv_bytes, expected_bytes))

    # --- committed JSON ------------------------------------------------------
    check("json summary.files == git-rederived files",
          js["summary"]["total_files"] == expected_files,
          "json=%r expected=%d" % (js["summary"]["total_files"], expected_files))
    check("json summary.bytes == git-rederived bytes",
          js["summary"]["total_bytes"] == expected_bytes,
          "json=%r expected=%d" % (js["summary"]["total_bytes"], expected_bytes))
    check("json summary.head_sha == recorded head_sha",
          js["summary"]["head_sha"] == head_sha,
          "json=%r head_sha=%r" % (js["summary"]["head_sha"], head_sha))
    check("json by_lane matches git re-derive",
          js["by_lane"] == {k: {"files": v[0], "bytes": v[1]}
                            for k, v in expected_lanes.items()},
          "json=%r git=%r" % (js["by_lane"], expected_lanes))
    check("json manifest.rowcount == git re-derive",
          len(js["manifest"]) == expected_files,
          "json=%d git=%d" % (len(js["manifest"]), expected_files))
    json_paths = {m["rel_path"] for m in js["manifest"]}
    git_paths = {m["rel_path"] for m in expected_manifest}
    check("json manifest.paths == git manifest.paths",
          json_paths == git_paths, "only-in-json=%d only-in-git=%d"
          % (len(json_paths - git_paths), len(git_paths - json_paths)))

    # --- manifest rows must be real committed blobs ---------------------------
    real_blobs = set()
    for line in tree.strip().splitlines():
        parts = line.split()
        if len(parts) == 5:
            _mode, otype, _obj, size_s, path = parts
            if otype == "blob":
                real_blobs.add(path[len(SCOPE):])
    manifest_paths = {m[0] for m in committed}
    check("csv paths are committed blobs",
          manifest_paths <= real_blobs,
          "missing=%d" % len(manifest_paths - real_blobs))

    # --- MD artifact -----------------------------------------------------------
    md_path = os.path.join(HERE, MD_NAME)
    with open(md_path, encoding="utf-8") as fh:
        md = fh.read()
    check("md contains per-lane table", "| sphinx | 1771" in md)
    check("md contains summary figure",
          "| committed files (blobs) | %d |" % expected_files in md)

    if failures:
        print("\n%d check(s) FAILED" % len(failures))
        return 1
    print("\nALL CHECKS PASSED (files=%d bytes=%d lanes=%d head_sha=%s)"
          % (expected_files, expected_bytes, len(expected_lanes), head_sha))
    return 0


if __name__ == "__main__":
    sys.exit(main())
