"""Pre-open schema/integrity/count proof; stdlib only, never constructs Store."""
import argparse
from contextlib import closing
import hashlib
import os
import re
import stat
import json
from pathlib import Path
import sqlite3


def inspect_readonly(path, *, _closed_snapshot=False):
    path = Path(path)
    if not path.is_file() or path.is_symlink():
        raise ValueError('existing nonsymlink private database required')
    uri = path.resolve().as_uri() + '?mode=ro' + ('&immutable=1' if _closed_snapshot else '')
    # sqlite3.Connection context management ends transactions; it does not close.
    with closing(sqlite3.connect(uri, uri=True, timeout=5)) as db:
        db.execute('PRAGMA query_only=ON')
        db.execute('BEGIN')
        version = db.execute('PRAGMA user_version').fetchone()[0]
        if version != 5:
            raise ValueError('pre-open database is not schema5; refuse migration')
        if db.execute('PRAGMA integrity_check').fetchall() != [('ok',)]:
            raise ValueError('read-only integrity check refused')
        lifecycle = {name: db.execute('SELECT COUNT(*) FROM ' + table).fetchone()[0]
                     for name, table in (('records', 'lifecycle_records'),
                                         ('events', 'lifecycle_events'),
                                         ('pending', 'lifecycle_pending'))}
        result = {'schema_version': version, 'lifecycle': lifecycle,
                  'outbox': dict(db.execute('SELECT state,COUNT(*) FROM outbox GROUP BY state')),
                  'submissions': dict(db.execute('SELECT state,COUNT(*) FROM submissions GROUP BY state')),
                  'integrity': 'ok', 'read_only_pre_open': True, 'store_constructed': False}
        db.rollback()
    return result


def inspect_closed_snapshot(path, expected_sha256):
    """Only a privately retained, frozen main-file snapshot with no WAL frames.

    Caller must establish exclusive snapshot creation/admin exit/no writer, and
    supply the recorded frozen main digest. Never use for the live database.
    Immutable SQLite reads ignore stale SHM and never create/change sidecars.
    Existing sidecars remain custody evidence; nothing is deleted/checkpointed.
    """
    path = Path(path)
    if re.fullmatch(r'[0-9a-f]{64}', expected_sha256) is None:
        raise ValueError('exact frozen snapshot digest required')
    def metadata(target):
        info = target.lstat()
        if not stat.S_ISREG(info.st_mode) or stat.S_IMODE(info.st_mode) != 0o600 or info.st_nlink != 1:
            raise ValueError('private single-link snapshot custody required')
        return info
    main = metadata(path)
    if not 0 < main.st_size <= 512 * 1024**2:
        raise ValueError('bounded frozen snapshot required')
    def sidecars():
        identities = {}
        for suffix in ('-wal', '-shm'):
            target = Path(str(path) + suffix)
            if os.path.lexists(target):
                info = metadata(target)
                if info.st_uid != main.st_uid or info.st_gid != main.st_gid:
                    raise ValueError('snapshot sidecar custody changed')
                if suffix == '-wal' and info.st_size != 0:
                    raise ValueError('snapshot has WAL frames; immutable read refused')
                identities[suffix] = (info.st_dev, info.st_ino, info.st_size, info.st_mtime_ns)
        return identities
    before_sidecars = sidecars()
    def digest():
        value = hashlib.sha256()
        with path.open('rb') as stream:
            for block in iter(lambda: stream.read(1024**2), b''):
                value.update(block)
        return value.hexdigest()
    if digest() != expected_sha256:
        raise ValueError('frozen main-file digest changed before inspection')
    proof = inspect_readonly(path, _closed_snapshot=True)
    after = metadata(path)
    if (after.st_dev, after.st_ino, after.st_uid, after.st_gid, after.st_size) != (main.st_dev, main.st_ino, main.st_uid, main.st_gid, main.st_size):
        raise ValueError('frozen main-file identity changed')
    if digest() != expected_sha256 or sidecars() != before_sidecars:
        raise ValueError('frozen snapshot changed during inspection')
    return proof


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--db', type=Path, required=True)
    args = parser.parse_args()
    try:
        print(json.dumps(inspect_readonly(args.db), sort_keys=True))
    except Exception:
        raise SystemExit('read-only schema5/integrity/count gate refused; no Store/admin open') from None
