#!/usr/bin/env python3
"""Compare READ CAPACITY(10) candidates before and after a GDR auth sequence."""
from __future__ import annotations
import argparse, json, sys
from pathlib import Path
from typing import Any

VERSION='v100'
PLAUSIBLE_BLOCK_LENGTHS = {512, 1024, 2048, 2056, 2064, 2324, 2336, 2352, 4096}

def load(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding='utf-8'))

def sanity(cap: dict[str, Any]) -> dict[str, Any]:
    block = cap.get('block_len_be')
    lba = cap.get('last_lba_be')
    plausible_block = isinstance(block, int) and block in PLAUSIBLE_BLOCK_LENGTHS
    plausible_lba = isinstance(lba, int) and 0 <= lba < 0x2000000
    plausible = bool(plausible_block and plausible_lba)
    reason = []
    if not plausible_block:
        reason.append(f"block_len_be={block} is not in common sector sizes")
    if not plausible_lba:
        reason.append(f"last_lba_be={lba} is outside the conservative optical-disc range")
    return {
        'plausible': plausible,
        'plausible_block_length': plausible_block,
        'plausible_lba': plausible_lba,
        'reason': '; '.join(reason) if reason else 'looks plausible as a READ CAPACITY(10) response',
    }

def cap_of(doc: dict[str, Any]) -> dict[str, Any]:
    cap = doc.get('read_capacity10_candidate') or {}
    out = {
        'source': doc.get('source_csv'),
        'cdb': doc.get('reconstructed_packet_cdb_hex'),
        'opcode': doc.get('reconstructed_packet_opcode'),
        'first_8_hex': cap.get('first_8_hex'),
        'last_lba_be': cap.get('last_lba_be'),
        'block_len_be': cap.get('block_len_be'),
        'sector_count_if_valid': cap.get('sector_count_if_valid'),
        'capacity_bytes_if_valid': cap.get('capacity_bytes_if_valid'),
        'df70_after_packet_sha256': (doc.get('df70_after_packet') or {}).get('sha256'),
        'df70_all_sha256': (doc.get('df70_all') or {}).get('sha256'),
        'offset': cap.get('offset'),
        'source_stream': cap.get('source_stream'),
        'candidate_only': True,
    }
    out['sanity'] = sanity(out)
    return out

def main(argv: list[str]) -> int:
    ap = argparse.ArgumentParser(description='Compare READ CAPACITY before/after auth sequence')
    ap.add_argument('--before', required=True, type=Path)
    ap.add_argument('--after', required=True, type=Path)
    ap.add_argument('--out-json', type=Path)
    ns = ap.parse_args(argv[1:])
    before = cap_of(load(ns.before))
    after = cap_of(load(ns.after))
    changed = (before.get('last_lba_be'), before.get('block_len_be')) != (after.get('last_lba_be'), after.get('block_len_be'))
    same_df70_after = before.get('df70_after_packet_sha256') == after.get('df70_after_packet_sha256')
    same_df70_all = before.get('df70_all_sha256') == after.get('df70_all_sha256')
    same_df70 = same_df70_after and same_df70_all
    meaningful = bool(changed and before['sanity']['plausible'] and after['sanity']['plausible'] and not same_df70)
    result = {
        'tool': 'compare_gdr_read_capacity.py',
        'version': VERSION,
        'before': before,
        'after': after,
        'changed': changed,
        'same_df70_after_packet_sha256': same_df70_after,
        'same_df70_all_sha256': same_df70_all,
        'meaningful_capacity_change_candidate': meaningful,
        'notes': [
            'READ CAPACITY is a valid authentication/unlock probe only when runs share state or the response is generated by a proven command-specific data phase.',
            'If before/after DF70 hashes are identical, the capacity comparison is still synthetic/non-command-specific.',
        ],
    }
    print(f"[READ-CAPACITY-COMPARE] version={VERSION}")
    print(f"[BEFORE] first8={before.get('first_8_hex')} last_lba={before.get('last_lba_be')} block={before.get('block_len_be')} bytes={before.get('capacity_bytes_if_valid')} plausible={before['sanity']['plausible']}")
    print(f"[AFTER]  first8={after.get('first_8_hex')} last_lba={after.get('last_lba_be')} block={after.get('block_len_be')} bytes={after.get('capacity_bytes_if_valid')} plausible={after['sanity']['plausible']}")
    print('[RESULT] changed=' + ('yes' if changed else 'no'))
    if same_df70:
        print('[RESULT] df70_sha256=same; before/after response bytes are unchanged')
    elif same_df70_after:
        print('[RESULT] df70_after_packet_sha256=same but df70_all differs; using scanned READ CAPACITY window from df70_all')
    if not before['sanity']['plausible'] or not after['sanity']['plausible']:
        print('[RESULT] capacity candidate failed sanity checks; do not interpret bytes as proven READ CAPACITY output yet')
    if meaningful:
        print('[RESULT] plausible capacity change candidate detected')
    elif not changed:
        print('[RESULT] no capacity change detected; either auth did not complete or the current emulator data phase/session model is still insufficient')
    if ns.out_json:
        ns.out_json.write_text(json.dumps(result, indent=2), encoding='utf-8')
        print(f"[OK] wrote {ns.out_json}")
    return 0

if __name__ == '__main__':
    raise SystemExit(main(sys.argv))
