"""tape_verifier.py — standalone verification of a sealed Agent TV tape.

stdlib-only. Given a tape directory, proves (or disproves, naming the exact
frame): manifest matches the frames file byte-for-byte; every frame's hash
chain link and Ed25519 signature verify; the genesis witness anchor matches
the manifest; the frame count is complete. Exit 0 = tape intact.

Usage: python tape_verifier.py <tape_dir>
"""
import hashlib, json, os, sys

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import seals  # noqa: E402


def verify(tape_dir):
    frames_p = os.path.join(tape_dir, 'frames.jsonl')
    man_p = os.path.join(tape_dir, 'manifest.json')
    faults = []
    if not os.path.exists(frames_p) or not os.path.exists(man_p):
        print('FAIL: tape incomplete — frames.jsonl and manifest.json required')
        return 1
    man = json.load(open(man_p, encoding='utf-8'))
    raw = open(frames_p, 'rb').read()
    if hashlib.sha256(raw).hexdigest() != man.get('frames_sha256'):
        faults.append('frames file does not match manifest sha256 — file touched after sealing')
    prev, n, seqs = 'GENESIS', 0, []
    genesis_witness = None
    for i, line in enumerate(open(frames_p, encoding='utf-8'), 1):
        line = line.strip()
        if not line:
            continue
        try:
            rec = json.loads(line)
        except ValueError:
            faults.append(f'line {i}: unparseable — chain corrupt')
            break
        verdict = seals.verify_record(prev, rec)
        if verdict != 'OK':
            faults.append(f'line {i} ({rec.get("kind")} seq {rec.get("seq")}): {verdict}')
        prev = rec.get('chain_seal') or rec.get('seal') or prev
        n += 1
        if rec.get('kind') == 'frame':
            seqs.append(rec.get('seq'))
        if rec.get('kind') == 'tape_genesis':
            genesis_witness = rec.get('witnessed_by')
    if seqs and seqs != list(range(1, len(seqs) + 1)):
        faults.append(f'frame sequence broken: {seqs[:8]}… — injection or deletion')
    if n - 1 != man.get('frames'):  # minus genesis
        faults.append(f'manifest says {man.get("frames")} frames, tape holds {n - 1}')
    if genesis_witness != man.get('witnessed_by'):
        faults.append('genesis witness anchor does not match manifest')
    if seals.chain_tip(frames_p) != man.get('tail_seal'):
        faults.append('tail seal mismatch — tape continued or truncated after manifest')
    if faults:
        print(f'FAIL — tape {man.get("tape_id")}: {len(faults)} fault(s)')
        for f in faults:
            print(f'  ✕ {f}')
        return 1
    print(f'PASS — tape {man.get("tape_id")}: {n - 1} frames, chain + signatures + '
          f'witness anchor all verify. No injection, no edit, no reorder.')
    return 0


if __name__ == '__main__':
    sys.exit(verify(sys.argv[1] if len(sys.argv) > 1 else '.'))
