"""Verify an actual SQLite backup and encrypted byte-for-byte recovery; no source deletion."""
import io,json,sqlite3,tempfile,zipfile,uuid
from pathlib import Path
from generated.secure_backup_vault import ForesixaBackupRotationEngine
from generated.archive_tax_reports import load_password,seal,key,MAGIC,MAX_ARCHIVE,publish
from infinbot_common import private_dir,private_read,strict_json,digest,timestamp,readonly_db,Rejected


def backup(config):
    target=private_dir(config['backup_dir'])
    password=load_password(config['archive_password_file'],True)
    with tempfile.TemporaryDirectory(prefix='.infinbot-recovery-',dir=target) as folder:
        root=Path(folder);root.chmod(0o700)
        report=ForesixaBackupRotationEngine(config['db_path'],root/'snapshot').execute_backup()
        if report['status']!='BACKUP_VERIFIED':raise Rejected('Actual ledger backup failed')
        snapshot=Path(report['backup_path'])
        if snapshot.stat().st_size>32*1024*1024:raise Rejected('Encrypted recovery currently supports ledgers up to 32 MiB; source preserved')
        raw=snapshot.read_bytes();sha=digest(snapshot)
        compressed=io.BytesIO()
        with zipfile.ZipFile(compressed,'w',zipfile.ZIP_DEFLATED) as z:
            z.writestr('ledger.sqlite3',raw);z.writestr('manifest.json',json.dumps({'sha256':sha,'format':'INFINBOT_SQLITE_RECOVERY_V1'}))
        encrypted=seal(compressed.getvalue(),password)
        archive=target/('infinbot_ledger_'+uuid.uuid4().hex+'.sqlite.aes')
        def recover(blob):
            from cryptography.hazmat.primitives.ciphers.aead import AESGCM
            head=blob[:len(MAGIC)+28];salt=head[len(MAGIC):len(MAGIC)+16];nonce=head[-12:]
            contents=AESGCM(key(password,salt)).decrypt(nonce,blob[len(head):],head)
            with zipfile.ZipFile(io.BytesIO(contents)) as z:
                if sorted(z.namelist())!=['ledger.sqlite3','manifest.json']:raise Rejected('Invalid backup members')
                if z.getinfo('ledger.sqlite3').file_size>32*1024*1024:raise Rejected('Expanded backup too large')
                restored=z.read('ledger.sqlite3')
            if restored!=raw:raise Rejected('Encrypted backup byte mismatch')
            return restored
        publish(archive,encrypted,verify=recover)
        recovered=root/'restored.sqlite3';publish(recovered,recover(private_read(archive,MAX_ARCHIVE)))
        with readonly_db(recovered) as c:
            if [r[0] for r in c.execute('PRAGMA integrity_check')]!=['ok']:raise Rejected('Restored ledger integrity failed')
        result={'status':'SELECTED_LEDGER_BACKUP_AND_ENCRYPTED_RESTORE_VERIFIED','observed_at':timestamp(),
                'archive_path':str(archive),'snapshot_sha256':sha,'source_deleted':False,'source_modified':False,
                'input_provenance':report['source_provenance'],
                'offsite_copy_verified':False,'worker_recovery_verified':False,'pruning_enabled':False}
        receipt=target/(archive.name+'.receipt.json');from infinbot_common import atomic_json
        atomic_json(receipt,result)
        return result


if __name__=='__main__':
    import argparse
    p=argparse.ArgumentParser();p.add_argument('--config',required=True);args=p.parse_args()
    try:print(json.dumps(backup(strict_json(private_read(args.config))),indent=2))
    except Exception:print(json.dumps({'status':'BACKUP_BLOCKED','source_deleted':False}));raise SystemExit(1)
