"""Read-only diagnosis, with original database/WAL evidence preserved first."""
import argparse
import datetime
import json
import pathlib
import shutil
import sqlite3

parser = argparse.ArgumentParser()
parser.add_argument("source", type=pathlib.Path)
parser.add_argument("output", type=pathlib.Path)
args = parser.parse_args()
args.output.mkdir(parents=True, exist_ok=False)
report = {"utc": datetime.datetime.now(datetime.timezone.utc).isoformat(), "databases": []}
for name in ("game-events.db", "markets.db"):
    source = args.source / name
    item = {"path": str(source), "files": [], "checks": {}}
    report["databases"].append(item)
    for suffix in ("", "-wal", "-shm"):
        src = pathlib.Path(str(source) + suffix)
        if src.exists():
            target = args.output / (name + suffix)
            shutil.copy2(src, target)
            item["files"].append({"name": target.name, "bytes": target.stat().st_size})
    print(json.dumps({"backed_up": name, "files": item["files"]}), flush=True)
    # Hold one SQLite read snapshot while checking, rather than opening the
    # forensic raw copy with a possibly incomplete live WAL copy.
    try:
        with sqlite3.connect(source.as_uri() + "?mode=ro", uri=True, timeout=10) as db:
            db.execute("PRAGMA query_only=ON")
            db.execute("BEGIN")
            for sql in ("PRAGMA quick_check(20)", "PRAGMA journal_mode", "PRAGMA page_size", "PRAGMA page_count", "PRAGMA freelist_count"):
                try:
                    item["checks"][sql] = db.execute(sql).fetchall()
                except sqlite3.DatabaseError as exc:
                    item["checks"][sql] = {"error": str(exc), "code": getattr(exc, "sqlite_errorcode", None)}
            try:
                tables = db.execute("SELECT type,name,tbl_name,rootpage,sql FROM sqlite_schema ORDER BY name").fetchall()
                item["schema"] = tables
                item["table_counts"] = {}
                for kind, table, _, _, _ in tables:
                    if kind != "table" or table.startswith("sqlite_"):
                        continue
                    try:
                        count = db.execute('SELECT COUNT(*) FROM "' + table.replace('"', '""') + '"').fetchone()[0]
                        item["table_counts"][table] = count
                    except sqlite3.DatabaseError as exc:
                        item["table_counts"][table] = {"error": str(exc), "code": getattr(exc, "sqlite_errorcode", None)}
            except sqlite3.DatabaseError as exc:
                item["schema_error"] = str(exc)
    except sqlite3.DatabaseError as exc:
        item["open_error"] = str(exc)
    (args.output / "diagnosis.json").write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
    print(json.dumps({"name": name, "checks": item["checks"], "table_counts": item.get("table_counts"), "error": item.get("open_error")}, ensure_ascii=False), flush=True)
