#!/usr/bin/env python3
import hashlib, json, sys

REQUIRED = {"record_id", "created_at", "kind", "payload", "provenance", "canonical_sha256", "prev_sha256"}


def canonical_bytes(obj):
    return json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()


def validate(lines):
    errors=[]; prev="0"*64; seen=set()
    for n, raw in enumerate(lines, 1):
        try: rec=json.loads(raw)
        except Exception as e:
            errors.append((n,"JSON_INVALID")); continue
        missing=REQUIRED-rec.keys()
        if missing: errors.append((n,"REQUIRED_FIELDS:"+",".join(sorted(missing))))
        rid=rec.get("record_id")
        if rid in seen: errors.append((n,"DUPLICATE_RECORD_ID"))
        seen.add(rid)
        if rec.get("prev_sha256") != prev: errors.append((n,"HASH_CHAIN"))
        material={k:rec.get(k) for k in ("record_id","created_at","kind","payload","provenance","prev_sha256")}
        got=hashlib.sha256(canonical_bytes(material)).hexdigest()
        if rec.get("canonical_sha256") != got: errors.append((n,"HASH_SELF"))
        prov=rec.get("provenance")
        if not isinstance(prov,dict) or not prov.get("source_ref") or not prov.get("observed_at"):
            errors.append((n,"PROVENANCE_REQUIRED"))
        if rec.get("kind")=="inherited" and rec.get("payload",{}).get("status") != "INHERITED_NOT_FACT":
            errors.append((n,"INHERITED_NOT_FACT"))
        prev=rec.get("canonical_sha256", prev)
    return errors

if __name__ == "__main__":
    errors=validate(sys.stdin.read().splitlines())
    print(json.dumps({"valid":not errors,"errors":[{"line":n,"code":c} for n,c in errors]}, sort_keys=True))
    sys.exit(1 if errors else 0)
