#!/usr/bin/env python3
"""Report v213 non-authoritative firmware-shadow 0x3E + READ CAPACITY + READ CAPACITY observer results.

This is a regression/handoff tool, not a claim that the live bridge is already
firmware-authoritative.  It checks that rows tagged with v213 shadow metadata
match the current bridge auth state and 0x3E response bytes.  Later versions can
replace the shadow source with an actual MN103S packet/FIFO/MMIO run while
keeping this report contract stable.
"""
from __future__ import annotations
import argparse, json, hashlib
from pathlib import Path
from typing import Any


def load_jsonl(path: Path) -> list[dict[str, Any]]:
    rows=[]
    with path.open('r', encoding='utf-8', errors='replace') as f:
        for line in f:
            line=line.strip()
            if not line:
                continue
            try:
                rows.append(json.loads(line))
            except Exception:
                pass
    return rows


def cdb_op(row: dict[str, Any]) -> str:
    h=str(row.get('cdb_hex') or '').strip()
    return h[:2].upper() if h else ''


def main() -> int:
    ap=argparse.ArgumentParser(description='GDR-8050L v213 firmware-shadow 0x3E + READ CAPACITY + READ CAPACITY observer report')
    ap.add_argument('jsonl', type=Path)
    ap.add_argument('--json', type=Path)
    ap.add_argument('--md', type=Path)
    args=ap.parse_args()
    rows=load_jsonl(args.jsonl)
    scsi=[r for r in rows if isinstance(r.get('index'), int) and int(r.get('index')) >= 0 and r.get('cdb_hex')]
    shadow=[r for r in scsi if r.get('firmware_shadow_3e_observed') or r.get('firmware_shadow_3e_enabled')]
    observed=[r for r in shadow if r.get('firmware_shadow_3e_observed')]
    mode_select=[r for r in observed if cdb_op(r) in ('15','55')]
    mode_sense=[r for r in observed if cdb_op(r) in ('1A','5A') and str(r.get('cdb_hex','')).split()[2:3] and (int(str(r.get('cdb_hex')).split()[2],16) & 0x3f)==0x3e]
    mismatches=[]
    for r in observed:
        if r.get('firmware_shadow_3e_bridge_agrees') is False:
            mismatches.append((r, 'bridge state disagrees with shadow state'))
        if 'firmware_shadow_3e_payload_match' in r and r.get('firmware_shadow_3e_payload_match') is False:
            mismatches.append((r, '0x3E payload differs from shadow expected payload'))
    events={}
    for r in observed:
        ev=str(r.get('firmware_shadow_3e_event') or r.get('state_event') or '')
        if ev:
            events[ev]=events.get(ev,0)+1
    auth_complete=all(events.get(x,0)>0 for x in ['challenge1','challenge2','partition1_unlock','sticky_descramble_mode31'])
    eject_relock=events.get('start_stop_eject',0)>0 or events.get('start_stop_load',0)>0
    ok = (len(mismatches) == 0 and len(observed) > 0 and auth_complete)
    out={
        'jsonl': str(args.jsonl),
        'rows': len(rows),
        'scsi_rows': len(scsi),
        'shadow_rows': len(shadow),
        'observed_shadow_rows': len(observed),
        'mode_select_shadow_rows': len(mode_select),
        'mode_sense_3e_shadow_rows': len(mode_sense),
        'event_counts': events,
        'auth_sequence_complete': auth_complete,
        'eject_or_load_observed': eject_relock,
        'mismatch_count': len(mismatches),
        'ok': ok,
        'note': 'v227 shadow is non-authoritative scaffold/observer; later firmware-in-loop should replace the shadow source while preserving report fields.',
    }
    if args.json:
        args.json.write_text(json.dumps(out, indent=2), encoding='utf-8')
    lines=['# GDR-8050L v213 firmware-shadow 0x3E + READ CAPACITY report','',
           f'- rows: {len(rows)}', f'- scsi_rows: {len(scsi)}', f'- observed_shadow_rows: {len(observed)}',
           f'- mode_select_shadow_rows: {len(mode_select)}', f'- mode_sense_3e_shadow_rows: {len(mode_sense)}',
           f'- auth_sequence_complete: {str(auth_complete).lower()}', f'- eject_or_load_observed: {str(eject_relock).lower()}',
           f'- mismatch_count: {len(mismatches)}', f'- ok: {str(out["ok"]).lower()}', '',
           '## Event counts','', '| event | count |', '|---|---:|']
    for k in sorted(events):
        lines.append(f'| `{k}` | {events[k]} |')
    lines += ['', '## Mismatches', '']
    if not mismatches:
        lines.append('None.')
    else:
        lines += ['| index | cdb | reason | source |', '|---:|---|---|---|']
        for r,reason in mismatches[:100]:
            lines.append(f"| {r.get('index')} | `{r.get('cdb_hex','')}` | {reason} | `{r.get('source','')}` |")
    lines += ['', '## Note', '', 'This report is intentionally non-authoritative in v213. It verifies the shadow-observer contract and creates the handoff surface for a later true MN103S firmware packet/FIFO/MMIO implementation.', '']
    if args.md:
        args.md.write_text('\n'.join(lines), encoding='utf-8')
    print(f"[FIRMWARE-SHADOW-3E] scsi={len(scsi)} observed={len(observed)} mode_select={len(mode_select)} mode_sense3e={len(mode_sense)} mismatches={len(mismatches)} ok={str(out['ok']).lower()}")
    return 0 if out['ok'] else 2

if __name__ == '__main__':
    raise SystemExit(main())
