#!/usr/bin/env python3
"""Compare Atari 5200 ROM collection against .dat files by CRC32."""

import binascii
import os
import re
import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).parent
DAT_DIR = SCRIPT_DIR / "dats"
ROM_DIR = SCRIPT_DIR.parent.parent / "rom_collections"

DAT_FILES = [
    "Atari-No-Intro-5200.dat",
    "Atari-Conversions-5200.dat",
    "Atari-Hacks-5200.dat",
    "Atari-Homebrews-5200.dat",
]

ROM_EXTENSIONS = {'.bin', '.a52', '.rom', '.car', '.hyb', '.dat'}


def parse_dat_file(filepath):
    text = filepath.read_text(encoding='utf-8', errors='replace')

    name_match = re.search(r'clrmamepro\s*\(.*?name\s+"([^"]+)"', text, re.DOTALL)
    collection = name_match.group(1) if name_match else filepath.stem

    entries = []
    for m in re.finditer(
        r'game\s*\(\s*name\s+"([^"]+)".*?rom\s*\(.*?size\s+(\d+)\s+crc\s+([0-9a-fA-F]+)',
        text, re.DOTALL
    ):
        entries.append({
            'name': m.group(1),
            'size': int(m.group(2)),
            'crc': int(m.group(3), 16),
            'collection': collection,
        })
    return entries


def parse_all_dats():
    db = {}
    for datname in DAT_FILES:
        path = DAT_DIR / datname
        if not path.exists():
            print(f"WARNING: {path} not found, skipping")
            continue
        for entry in parse_dat_file(path):
            db.setdefault(entry['crc'], []).append(entry)
    return db


def compute_crc(data):
    return binascii.crc32(data) & 0xFFFFFFFF


def scan_roms(directory):
    found = {}
    for root, _, files in os.walk(directory):
        for fname in files:
            ext = os.path.splitext(fname)[1].lower()
            if ext not in ROM_EXTENSIONS:
                continue
            fpath = os.path.join(root, fname)
            try:
                data = open(fpath, 'rb').read()
            except OSError as e:
                print(f"WARNING: cannot read {fpath}: {e}")
                continue
            crc = compute_crc(data)
            found.setdefault(crc, []).append({'path': fpath, 'size': len(data)})
    return found


def report(dat_db, rom_crcs):
    collections = {}
    for crc, entries in dat_db.items():
        for e in entries:
            c = e['collection']
            collections.setdefault(c, []).append(e)

    total_dat = 0
    total_found = 0
    total_missing = 0
    all_missing = []

    for cname in sorted(collections.keys()):
        entries = sorted(collections[cname], key=lambda e: e['name'])
        found = [e for e in entries if e['crc'] in rom_crcs]
        missing = [e for e in entries if e['crc'] not in rom_crcs]

        total_dat += len(entries)
        total_found += len(found)
        total_missing += len(missing)
        all_missing.extend(missing)

        print(f"\n--- {cname} ({len(entries)} entries) ---")
        print(f"FOUND: {len(found)}/{len(entries)}")
        if missing:
            print(f"MISSING ({len(missing)}):")
            for e in missing:
                print(f"  {e['name']}  [crc:{e['crc']:08x} size:{e['size']}]")

    print(f"\n{'='*60}")
    print(f"TOTAL IN DATS: {total_dat}")
    print(f"FOUND:         {total_found}")
    print(f"MISSING:       {total_missing}")

    unmatched = []
    dat_crc_set = set(dat_db.keys())
    for crc, files in rom_crcs.items():
        if crc not in dat_crc_set:
            for f in files:
                unmatched.append((crc, f['path'], f['size']))

    if unmatched:
        print(f"\nUNMATCHED FILES ({len(unmatched)} — in collection but not in any dat):")
        for crc, path, size in sorted(unmatched, key=lambda x: x[1]):
            print(f"  {path}  [crc:{crc:08x} size:{size}]")


def main():
    if not ROM_DIR.exists():
        print(f"ERROR: rom_collections dir not found at {ROM_DIR}")
        sys.exit(1)

    print(f"Parsing dat files from {DAT_DIR} ...")
    dat_db = parse_all_dats()
    unique_crcs = len(dat_db)
    total_entries = sum(len(v) for v in dat_db.values())
    print(f"  {total_entries} entries, {unique_crcs} unique CRCs")

    print(f"\nScanning ROMs in {ROM_DIR} ...")
    rom_crcs = scan_roms(ROM_DIR)
    total_files = sum(len(v) for v in rom_crcs.values())
    print(f"  {total_files} files, {len(rom_crcs)} unique CRCs")

    report(dat_db, rom_crcs)


if __name__ == '__main__':
    main()
