#!/usr/bin/env python3
"""Report media/layout handling for GDR/XDVD live traces.

v227 focuses on corrected option-1 Redump-style images.  The report is tolerant
of legacy v206-v227 traces that do not carry media-profile fields, but when a
.media.json-backed Redump layout is observed it verifies that the trace uses the
profile-derived mapping contract rather than the old single global 306080 delta.
"""
from __future__ import annotations
import argparse, collections, json
from pathlib import Path
from typing import Any


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


def intish(v: Any, default: int | None = None) -> int | None:
    try:
        if v is None or v == '': return default
        return int(v)
    except Exception:
        return default


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


def is_read(row: dict[str, Any]) -> bool:
    return op(row) in ('28','A8')


def main() -> int:
    ap=argparse.ArgumentParser(description='GDR/XDVD v227 media layout 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)
    reads=[r for r in rows if is_read(r)]
    layout_counts=collections.Counter(str(r.get('media_layout_type') or '') for r in reads)
    note_counts=collections.Counter(str(r.get('read_map_note') or '') for r in reads)
    redump=[r for r in reads if str(r.get('media_is_redump_style')).lower() in ('true','1') or r.get('media_is_redump_style') is True]
    profile_loaded=[r for r in reads if str(r.get('media_profile_loaded')).lower() in ('true','1') or r.get('media_profile_loaded') is True]
    effective_deltas=collections.Counter(intish(r.get('effective_media_lba_delta'), 0) for r in reads if intish(r.get('effective_media_lba_delta'), None) is not None)
    redump_deltas=collections.Counter(intish(r.get('effective_media_lba_delta'), 0) for r in redump if intish(r.get('effective_media_lba_delta'), None) is not None)
    segment_counts=collections.Counter(intish(r.get('media_segment_count'), 1) for r in reads)
    sources=collections.Counter(str(r.get('source') or '') for r in reads)
    outside=[r for r in redump if 'outside' in str(r.get('read_map_note') or '').lower()]
    old_delta_redump=[r for r in redump if str(r.get('dynamic_media_auth_stage') or r.get('firmware_shadow_3e_stage') or '').lower()=='unlocked' and intish(r.get('effective_media_lba_delta'), None)==306080]
    unlocked_redump=[r for r in redump if str(r.get('dynamic_media_auth_stage') or r.get('firmware_shadow_3e_stage') or '').lower()=='unlocked']
    unlocked_redump_deltas=collections.Counter(intish(r.get('effective_media_lba_delta'), 0) for r in unlocked_redump if intish(r.get('effective_media_lba_delta'), None) is not None)
    redump_unlocked_delta=unlocked_redump_deltas.most_common(1)[0][0] if unlocked_redump_deltas else None

    if redump:
        ok = bool(profile_loaded) and not outside and not old_delta_redump and bool(unlocked_redump)
        mode='redump_profile'
        note='Redump-style media profile observed; READ rows should use layout-derived segments/deltas.'
    else:
        ok = True
        mode='legacy_or_no_media_profile'
        note='No Redump-style media-profile rows observed; legacy image handling remains in use.'

    report={
        'jsonl': str(args.jsonl),
        'rows': len(rows),
        'read_rows': len(reads),
        'mode': mode,
        'media_profile_loaded_read_rows': len(profile_loaded),
        'redump_read_rows': len(redump),
        'layout_counts': dict(layout_counts),
        'read_map_note_counts': dict(note_counts),
        'effective_delta_counts': dict(sorted(effective_deltas.items(), key=lambda kv: kv[0])),
        'redump_effective_delta_counts': dict(sorted(redump_deltas.items(), key=lambda kv: kv[0])),
        'redump_unlocked_effective_delta_counts': dict(sorted(unlocked_redump_deltas.items(), key=lambda kv: kv[0])),
        'redump_unlocked_candidate_delta': redump_unlocked_delta,
        'segment_count_distribution': dict(sorted(segment_counts.items(), key=lambda kv: kv[0] if kv[0] is not None else -1)),
        'source_counts': dict(sources),
        'redump_outside_mapping_rows': len(outside),
        'redump_unlocked_old_306080_rows': len(old_delta_redump),
        'ok': ok,
        'note': note,
    }
    if args.json:
        args.json.write_text(json.dumps(report, indent=2), encoding='utf-8')
    lines=['# GDR/XDVD v227 media layout report','',
           f'- rows: {len(rows)}', f'- read_rows: {len(reads)}', f'- mode: `{mode}`',
           f'- media_profile_loaded_read_rows: {len(profile_loaded)}', f'- redump_read_rows: {len(redump)}',
           f'- redump_unlocked_candidate_delta: `{redump_unlocked_delta}`',
           f'- redump_outside_mapping_rows: {len(outside)}', f'- redump_unlocked_old_306080_rows: {len(old_delta_redump)}',
           f'- ok: {str(ok).lower()}', '',
           '## Counts','',
           f'- layout_counts: `{dict(layout_counts)}`',
           f'- read_map_note_counts: `{dict(note_counts)}`',
           f'- effective_delta_counts: `{dict(sorted(effective_deltas.items(), key=lambda kv: kv[0]))}`',
           f'- redump_unlocked_effective_delta_counts: `{dict(sorted(unlocked_redump_deltas.items(), key=lambda kv: kv[0]))}`',
           f'- segment_count_distribution: `{dict(sorted(segment_counts.items(), key=lambda kv: kv[0] if kv[0] is not None else -1))}`', '',
           '## Note','', note, '']
    if args.md:
        args.md.write_text('\n'.join(lines), encoding='utf-8')
    print(f"[MEDIA-LAYOUT] mode={mode} reads={len(reads)} redump_reads={len(redump)} profile_loaded_reads={len(profile_loaded)} old_306080_redump_rows={len(old_delta_redump)} ok={str(ok).lower()}")
    return 0 if ok else 2

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