#!/usr/bin/env python3
"""Build a Nexum file-only upgrade from an explicit reviewed path list."""
import argparse,hashlib,json,re,zipfile
from pathlib import Path
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--root',type=Path,default=Path(__file__).resolve().parents[1])
parser.add_argument('--paths',type=Path,required=True,help='UTF-8 file: one reviewed relative path per line')
parser.add_argument('--output',type=Path,required=True)
parser.add_argument('--min-version',default='3.10.0')
args=parser.parse_args();root=args.root.resolve()
version=re.search(r'\$version\s*=\s*[\'"]([^\'"]+)',(root/'app/Config/Evolution.php').read_text())[1]
paths=[p.strip() for p in args.paths.read_text().splitlines() if p.strip() and not p.startswith('#')]
if 'app/Config/Evolution.php' not in paths:paths.append('app/Config/Evolution.php')
config={'app/Common.php','app/Config/Evolution.php','app/Config/Gensou.php','app/Config/Routes.php','app/Config/Filters.php','app/Config/Events.php','app/Config/Services.php'}
prefixes=('app/Controllers/','app/Services/','app/Models/','app/Views/','app/Filters/','app/Helpers/','app/Libraries/','app/Commands/','app/Entities/','app/Language/','public/assets/css/','public/assets/js/','public/assets/font/','public/assets/img/','public/assets/audio/','public/assets/video/')
files={}
for path in dict.fromkeys(paths):
 parts=Path(path).parts
 if path.startswith('/') or '..' in parts or '\\' in path or ':' in path or path not in config and not path.startswith(prefixes):raise SystemExit('Protected or unsupported path: '+path)
 if any(part.lower() in {'.git','upload','uploads','backup','backups'} or part.lower().startswith('.env') for part in parts):raise SystemExit('Protected path: '+path)
 target=root/path
 if target.is_symlink() or root not in target.resolve().parents:raise SystemExit('Symlink or invalid path: '+path)
 files[path]=target.read_bytes()
manifest={'product':'nexum-ai','format':1,'version':version,'min_version':args.min_version,'files':{p:hashlib.sha256(b).hexdigest() for p,b in files.items()}}
args.output.parent.mkdir(parents=True,exist_ok=True)
with zipfile.ZipFile(args.output,'w',zipfile.ZIP_DEFLATED) as archive:
 archive.writestr('nexum-update.json',json.dumps(manifest,ensure_ascii=False,indent=2))
 for path,content in files.items():archive.writestr(path,content)
print(f'{args.output}: {version}, {len(files)} files')
