"""Synthetic citation-integrity teaching example. Not an action authorizer."""
import copy
import hashlib
import json
import sys
from pathlib import Path


def strict_object(pairs):
    result = {}
    for key, value in pairs:
        if key in result:
            raise ValueError("duplicate JSON key: " + key)
        result[key] = value
    return result


def load_bounded(path):
    with Path(path).open("rb") as stream:
        raw = stream.read(65537)
    if len(raw) > 65536:
        raise ValueError("teaching example accepts at most 64 KiB per input")
    return json.loads(raw, object_pairs_hook=strict_object)


def check(sources, candidate, target_version):
    if not isinstance(sources, dict) or not isinstance(candidate, dict):
        raise ValueError("expected JSON objects")
    if set(candidate) != {"claim", "source_id", "quote"}:
        raise ValueError("expected claim, source_id and quote only")
    for key in candidate:
        if not isinstance(candidate[key], str) or not candidate[key].strip():
            raise ValueError("candidate fields must be nonempty strings")
    if len(candidate["quote"]) < 20:
        raise ValueError("quote too short for this teaching example")
    source = sources.get(candidate["source_id"])
    if not isinstance(source, dict):
        raise ValueError("source ID absent from trusted packet")
    for key in ("text", "version", "effective_date", "sha256"):
        if not isinstance(source.get(key), str) or not source[key]:
            raise ValueError("incomplete trusted source metadata")
    actual = hashlib.sha256(source["text"].encode("utf-8")).hexdigest()
    if actual != source["sha256"]:
        raise ValueError("captured source digest changed")
    if source["version"] != target_version:
        raise ValueError("source version differs from reviewer target")
    if candidate["quote"] not in source["text"]:
        raise ValueError("quote absent from captured text")
    return {"status": "citation-integrity-passed",
            "source_id": candidate["source_id"],
            "version": source["version"],
            "effective_date": source["effective_date"],
            "semantic_review": "required",
            "source_freshness": "not established",
            "execution_authorization": "not established"}


def self_test():
    text = "For release 2.4, preserve the diagnostic buffer before any restart."
    packet = {"runbook-24": {"text": text, "version": "2.4",
              "effective_date": "2026-10-10",
              "sha256": hashlib.sha256(text.encode()).hexdigest()}}
    good = {"claim": "Inspect the preservation requirement.",
            "source_id": "runbook-24", "quote": text}
    check(packet, good, "2.4")
    failures = [({**good, "source_id": "missing"}, packet, "2.4"),
                ({**good, "quote": "Restart immediately without preserving anything."}, packet, "2.4"),
                (good, packet, "2.3"),
                ({**good, "quote": "For release"}, packet, "2.4"),
                ({**good, "claim": True}, packet, "2.4")]
    altered = copy.deepcopy(packet)
    altered["runbook-24"]["text"] += " Changed."
    failures.append((good, altered, "2.4"))
    for draft, sources, target in failures:
        try:
            check(sources, draft, target)
        except ValueError:
            continue
        raise AssertionError("expected citation check failure")
    try:
        json.loads('{"claim":"a","claim":"b"}', object_pairs_hook=strict_object)
    except ValueError:
        pass
    else:
        raise AssertionError("duplicate key accepted")
    # This deliberately wrong interpretation still passes structural checks.
    misleading = {**good, "claim": "Release 2.4 permits an immediate restart."}
    assert check(packet, misleading, "2.4")["semantic_review"] == "required"
    print("Synthetic self-test passed: 2 structural passes, 7 expected rejections; semantic limitation demonstrated.")


if __name__ == "__main__":
    if sys.argv[1:] == ["--self-test"]:
        self_test()
    elif len(sys.argv) == 4:
        try:
            print(json.dumps(check(load_bounded(sys.argv[1]),
                                   load_bounded(sys.argv[2]), sys.argv[3]), indent=2))
        except (ValueError, OSError, TypeError) as error:
            print(json.dumps({"status": "citation-check-failed", "reason": str(error)}))
            sys.exit(1)
    else:
        print("Usage: python3 incident-citation-check.py sources.json candidate.json TARGET_VERSION")
        sys.exit(2)
