"""Resume the existing verified backup download using bounded read-only SSH ranges."""
from concurrent.futures import ThreadPoolExecutor, as_completed
import hashlib
import argparse
import re
import importlib.util
import json
import os
from pathlib import Path
import shlex
import shutil
import subprocess

os.umask(0o077)
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location('deployment_client', ROOT / 'scripts/deploy.py')
client = importlib.util.module_from_spec(spec)
spec.loader.exec_module(client)
config = client.configuration(ROOT / '.deploy/config.json')
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--release', default='b2351e7b71a4c78ea0b83ca43f2f8689963f2594')
release = parser.parse_args().release
if not re.fullmatch('[a-f0-9]{40}', release):
    raise ValueError('Full reviewed release required')
folder = ROOT / '.deploy/backups' / release
folder.mkdir(exist_ok=True, mode=0o700)
remote_folder = f"{config['deploy_dir']}/backups/{release}"
ssh = ['ssh', '-p', str(config['port']), *client.ssh_options(config), f"{config['user']}@{config['host']}"]
client.copy(config, remote_folder + '/manifest.json', folder / 'manifest.json', download=True)
manifest = json.loads((folder / 'manifest.json').read_text())
if manifest.get('release') != release or manifest.get('app_dir') != config['app_dir']:
    raise ValueError('Unexpected backup identity')
chunk_size = 8 * 1024 * 1024
path = remote_folder + '/app.tar.gz'
metadata_code = '''import hashlib,json
from pathlib import Path
p=Path(PATH)
chunks=[]
with p.open('rb') as f:
 while True:
  value=f.read(SIZE)
  if not value:break
  chunks.append(hashlib.sha256(value).hexdigest())
print(json.dumps({'size':p.stat().st_size,'chunks':chunks}))
'''.replace('PATH', repr(path)).replace('SIZE', str(chunk_size))
result = subprocess.run([*ssh, 'python3 -'], input=metadata_code, text=True, capture_output=True, check=True, timeout=90)
metadata = json.loads(result.stdout)
partial = folder / '.app.tar.gz.ranges-partial'
if not partial.exists():
    candidates = [folder / '.app.tar.gz.partial', folder / 'app.tar.gz']
    candidates += sorted(folder.parent.glob('*/app.tar.gz'), key=lambda p: p.stat().st_mtime, reverse=True)
    basis = next((p for p in candidates if p.is_file()), None)
    if basis: shutil.copyfile(basis, partial)
    else: partial.touch(mode=0o600)
with partial.open('r+b') as stream: stream.truncate(metadata['size'])
partial.chmod(0o600)
pending=[]
with partial.open('rb') as stream:
    for index, expected in enumerate(metadata['chunks']):
        value=stream.read(chunk_size)
        if hashlib.sha256(value).hexdigest()!=expected:pending.append(index)
print(f'Archive chunks verified/reused: {len(metadata["chunks"])-len(pending)}/{len(metadata["chunks"])}',flush=True)

def fetch(index):
    offset = index * chunk_size
    size = min(chunk_size, metadata['size'] - offset)
    code = f"import sys;f=open({path!r},'rb');f.seek({offset});sys.stdout.buffer.write(f.read({size}))"
    for attempt in range(3):
        result = subprocess.run([*ssh, 'python3 -c ' + shlex.quote(code)], capture_output=True, timeout=240)
        if result.returncode == 0 and len(result.stdout)==size and hashlib.sha256(result.stdout).hexdigest()==metadata['chunks'][index]:
            with partial.open('r+b',buffering=0) as stream:
                stream.seek(offset);stream.write(result.stdout)
            return index
    raise RuntimeError(f'Backup range {index} failed; verified ranges retained')

with ThreadPoolExecutor(max_workers=3) as executor:
    futures = [executor.submit(fetch,index) for index in pending]
    for number,future in enumerate(as_completed(futures),1):
        future.result()
        print(f'Archive ranges downloaded and verified: {number}/{len(pending)}',flush=True)
if client.digest(partial)!=manifest['checksums']['app.tar.gz']:
    raise ValueError('Final archive checksum mismatch; do not promote')
partial.replace(folder / 'app.tar.gz')
for name in ['database.sql.gz','pm2.json']:
    target=folder/name
    if target.exists() and client.digest(target)==manifest['checksums'][name]:continue
    source=remote_folder+'/'+name
    query='python3 -c '+shlex.quote(f"import os;print(os.path.getsize({source!r}))")
    size=int(subprocess.check_output([*ssh,query],timeout=30))
    candidate=folder/('.'+name+'.range-partial')
    with candidate.open('wb') as stream:
        for offset in range(0,size,1024*1024):
            amount=min(1024*1024,size-offset)
            code=f"import sys;f=open({source!r},'rb');f.seek({offset});sys.stdout.buffer.write(f.read({amount}))"
            for attempt in range(3):
                chunk=subprocess.run([*ssh,'python3 -c '+shlex.quote(code)],capture_output=True,timeout=90)
                if chunk.returncode==0 and len(chunk.stdout)==amount:break
            else:raise RuntimeError('Small backup range failed')
            stream.write(chunk.stdout)
    candidate.chmod(0o600)
    if client.digest(candidate)!=manifest['checksums'][name]:raise ValueError('Backup checksum mismatch')
    candidate.replace(target)
    print(f'{name}: full SHA-256 verified',flush=True)
print('All fresh off-server app/database/PM2 backup checksums verified',flush=True)
