"""Create only the new stopped Compose stack, then adopt it with the common ct installer."""
import json
import os
from pathlib import Path
import subprocess
import sys

STAGE=Path('/storage/contextra/deploy/ai2-20261006-r01')
SOURCE=Path('/workspace/contextra/source/4f0bd4e-ai2-tools-r01')
SITE=Path('/storage/contextra/site/ai2-20261006-r01')
PROJECT='contextra-ai2'

def cmd(args,timeout=30):
    return subprocess.check_output(args,text=True,stderr=subprocess.STDOUT,timeout=timeout)

def main():
    os.umask(0o077)
    assert cmd(['hostname']).strip()=='icertirnd-ai'
    assert not Path('/etc/contextra-maintenance/server.json').exists()
    images=json.loads((STAGE/'images-resolved.json').read_text())
    receipts=json.loads((STAGE/'models-result.json').read_text())
    assert set(receipts)=={'medium','pose','fire','crowd'}
    args=['docker','compose','--project-directory',str(SOURCE),'-p',PROJECT,'--env-file',str(SITE/'runtime.env')]
    for path in (SOURCE/'docker-compose.yml',SITE/'site.compose.json',SOURCE/'deploy/secure-bridge.compose.yml',SOURCE/'deploy/web-start.compose.yml'):
        args+=['-f',str(path)]
    doc=json.loads(cmd(args+['config','--format','json']))
    roles={'analytics','ai-control-sidecar','ai-gateway','redis','postgresql'}
    doc['services']={k:v for k,v in doc['services'].items() if k in roles}
    assert set(doc['services'])==roles
    for role,cfg in doc['services'].items():
        assert cfg['image']==images[role]
        assert json.loads(cmd(['docker','image','inspect',images[role]]))[0]['Id']==images[role]
        cfg.pop('build',None)
        cfg['restart']='no'
    used={m['source'] for cfg in doc['services'].values() for m in cfg.get('volumes',[]) if m['type']=='volume'}
    doc['volumes']={k:v for k,v in doc.get('volumes',{}).items() if k in used}
    for kind,key in (('volume','volumes'),('network','networks')):
        for name,definition in doc.get(key,{}).items():
            assert not definition.get('external'), 'Fresh install cannot adopt unknown external resources'
            actual=definition.get('name',PROJECT+'_'+name)
            prior=subprocess.run(['docker',kind,'inspect',actual],capture_output=True,text=True,timeout=10)
            assert prior.returncode!=0, 'Existing resource requires explicit ownership review: '+actual
            error=prior.stderr.lower()
            assert ('no such '+kind in error or (kind=='network' and 'network '+actual+' not found' in error)), 'Cannot verify resource absence'
    initial=SITE/'bootstrap.compose.json'
    assert not initial.exists()
    initial.write_text(json.dumps(doc,indent=2)+'\n');initial.chmod(0o600)
    name='contextra-ai2-redis-uid-probe-20261006'
    try:
        raw=cmd(['docker','run','--rm','--name',name,'--pull=never','--network=none','--cpus=1','--memory=128m',
            '--pids-limit=32','--entrypoint','id',images['redis'],'redis'])
        import re
        uid=int(re.search(r'uid=(\d+)',raw)[1]);gid=int(re.search(r'gid=(\d+)',raw)[1])
        os.chown(SITE/'redis/users.acl',uid,gid)
    finally:
        probe=subprocess.run(['docker','inspect',name],capture_output=True,timeout=10)
        if probe.returncode==0:cmd(['docker','rm','-f',name])
    create=['docker','compose','--project-directory',str(SOURCE),'-p',PROJECT,'-f',str(initial)]
    cmd(create+['create','--no-build','--pull','never'],180)
    sys.path.insert(0,str(SOURCE/'tools/icerti_offline'))
    import install_portable as installer
    d,p,original,sealed,rows=installer.discover(PROJECT,'si','/workspace/contextra')
    d['server']='icerti-ai2'
    p['id']='internal';p['label']='아이서티 내부 테스트망'
    p['redis_allow']=['192.168.30.18']
    # New dedicated chain, never reuse an old application's global firewall configuration.
    fw=SITE/'firewall.py'
    d['firewall']={'script':str(fw),'chain':'CTX_AI2_REDIS','unit':'contextra-ai2-redis-access.service'}
    installer.server.validate(d);installer.bind_context(d)
    installer.install(d,p,original,sealed,rows)
    prefix=Path(d['paths']['tools'])
    installer.fp.atomic(fw,('import sys\nsys.path.insert(0,'+repr(str(prefix))+')\nfrom portable_firewall import apply\napply()\n').encode())
    installer.fp.atomic(SITE/'access.json',{'host':'192.168.30.52','port':16379,'readers':['192.168.30.18']})
    installer.fp.atomic(STAGE/'ct-installed.json',{'server':d['server'],'prefix':str(prefix),
        'source':str(SOURCE),'profile':p['id'],'runtime_started':False,'enrolled':False,
        'project':PROJECT,'image_ids':images,'compose':str(initial)})
    print('CT_INSTALLED_SERVICES_STOPPED_ENROLLMENT_PENDING')

if __name__=='__main__':main()
