#!/usr/bin/env python3
"""Validate an Xbox raw-disc .xdvd.json sidecar and response payload files."""
from __future__ import annotations
import argparse, hashlib, sys
from pathlib import Path
from xdvd_sidecar import XDVDSidecar, bytes_to_hex, hex_to_bytes

VERSION = "v100"


def be32(data: bytes) -> int:
    if len(data) != 4:
        raise ValueError("be32 needs exactly 4 bytes")
    return int.from_bytes(data, "big")


def check_capacity(label: str, data: bytes) -> bool:
    ok = True
    if len(data) != 8:
        print(f"[FAIL] {label} READ CAPACITY length={len(data)} expected=8")
        return False
    last_lba = be32(data[:4])
    block = be32(data[4:8])
    sectors = last_lba + 1
    plausible = block == 2048 and 0 < sectors < 0x2000000
    print(f"[{ 'OK' if plausible else 'FAIL' }] {label} READ CAPACITY {bytes_to_hex(data)} last_lba={last_lba} sectors={sectors} block={block}")
    return plausible


def main(argv: list[str]) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("sidecar", type=Path)
    ns = ap.parse_args(argv[1:])
    sc = XDVDSidecar(ns.sidecar)
    print(f"[XDVD] validator={VERSION} path={sc.path}")
    summary = sc.summary()
    print(f"[XDVD] format={summary.get('format')} version={summary.get('version')} image={summary.get('image_file')}")
    print(f"[XDVD] sectors={summary.get('sector_count')} bytes={summary.get('byte_count')} sha1={summary.get('sha1')}")
    ok = True
    states = sc.drive_states
    for state in ("locked", "unlocked"):
        if state not in states:
            print(f"[FAIL] missing drive state {state}")
            ok = False
            continue
        raw = states[state]
        try:
            cap = hex_to_bytes(raw.get("read_capacity_10_hex", ""))
            ok &= check_capacity(state, cap)
        except Exception as exc:
            print(f"[FAIL] {state} READ CAPACITY parse: {exc}")
            ok = False
        try:
            ms = hex_to_bytes(raw.get("mode_sense_3e_hex", ""))
            good = len(ms) == 28 and len(raw.get("mode_sense_3e_cdb_hex", "")) >= 20
            print(f"[{ 'OK' if good else 'FAIL' }] {state} MODE SENSE 3E len={len(ms)} first={bytes_to_hex(ms[:16])}")
            ok &= good
        except Exception as exc:
            print(f"[FAIL] {state} MODE SENSE parse: {exc}")
            ok = False
    for item in sc.data.get("scsi_responses", []) or []:
        rel = item.get("response_file")
        if not rel:
            print(f"[FAIL] response without response_file: {item}")
            ok = False
            continue
        p = Path(rel)
        if not p.is_absolute():
            p = sc.base_dir / p
        if not p.exists():
            print(f"[FAIL] missing response file: {p}")
            ok = False
            continue
        data = p.read_bytes()
        expected = int(item.get("data_len", len(data)))
        good = len(data) == expected
        print(f"[{ 'OK' if good else 'FAIL' }] {item.get('name')} len={len(data)} expected={expected} sha1={hashlib.sha1(data).hexdigest()} file={p.name}")
        ok &= good
    if ok:
        print("[OK] sidecar validation passed")
        return 0
    print("[FAIL] sidecar validation failed")
    return 1


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