"""Install only the voice WebRTC sidecar, one Apache route and UDP 7012.

Existing VoiceTcp/game binaries, data, databases and service state stay intact.
The immutable deployment directory contains an exact Apache rollback copy.
"""
import hashlib,json,os,pathlib,shutil,subprocess,sys,time,urllib.request

expected=sys.argv[1]
assert len(expected)==64 and all(c in '0123456789abcdef' for c in expected)
root=pathlib.Path('/var/www/html/ro-th-online')
source=root/'staging/voice-rtc-gateway-20261001'
assert hashlib.sha256(source.read_bytes()).hexdigest()==expected
notices=root/'staging/voice-rtc-notices-20261001.txt'
assert notices.is_file() and notices.stat().st_size>1000
deploy=root/'deploy/voice-rtc-20261001'
config=pathlib.Path('/etc/apache2/sites-enabled/zz-ro-th-download-ssl.conf').resolve()
unit=pathlib.Path('/etc/systemd/system/ro-th-online-voice-rtc.service')
binary=root/'voice-rtc/voice-rtc-gateway'
assert not deploy.exists() and not unit.exists() and not binary.exists()

def pids(name):
    return subprocess.check_output(['pgrep','-x',name],text=True).strip().splitlines()

before={name:pids(name) for name in ('map-server','voice-server','login-server','char-server')}
original=config.read_text()
needle='    ProxyPass /bridge/ ws://127.0.0.1:8088/bridge/ retry=0'
assert original.count(needle)==1 and '/bridge/voice-rtc' not in original
deploy.mkdir()
shutil.copy2(config,deploy/'apache-before.conf')
binary.parent.mkdir(exist_ok=True)
shutil.copy2(source,binary);binary.chmod(0o755)
shutil.copy2(notices,binary.parent/'THIRD_PARTY_NOTICES.txt')
unit.write_text('''[Unit]
Description=Ro-Thailand WebRTC proximity voice bridge
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/html/ro-th-online/voice-rtc
ExecStart=/var/www/html/ro-th-online/voice-rtc/voice-rtc-gateway --listen 127.0.0.1:8090 --upstream 127.0.0.1:7010 --origin https://ro-th.online --udp 0.0.0.0:7012 --public-ip 43.228.86.71
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
CapabilityBoundingSet=
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
MemoryMax=512M

[Install]
WantedBy=multi-user.target
''')
route='''    # WebRTC signaling only; voice audio uses DTLS/SCTP/UDP 7012.
    ProxyPass /bridge/voice-rtc ws://127.0.0.1:8090/bridge/voice-rtc retry=0
    ProxyPassReverse /bridge/voice-rtc ws://127.0.0.1:8090/bridge/voice-rtc
'''
try:
    subprocess.run(['systemctl','daemon-reload'],check=True)
    subprocess.run(['systemctl','start','ro-th-online-voice-rtc'],check=True)
    for attempt in range(20):
        try:
            assert urllib.request.urlopen('http://127.0.0.1:8090/health',timeout=2).read()==b'voice-rtc-v1\n'
            break
        except OSError:
            time.sleep(.2)
    else:
        raise RuntimeError('WebRTC health failed')
    config.write_text(original.replace(needle,route+needle))
    subprocess.run(['apache2ctl','configtest'],check=True)
    subprocess.run(['ufw','allow','7012/udp','comment','Ro-Thailand WebRTC voice'],check=True)
    subprocess.run(['systemctl','reload','apache2'],check=True)
    subprocess.run(['systemctl','enable','ro-th-online-voice-rtc'],check=True)
    after={name:pids(name) for name in before}
    assert before==after,'Existing game/voice PIDs changed'
    result=dict(binarySha256=expected,gameServicePidsUnchanged=after,udpPort=7012,
                signaling='wss://ro-th.online/bridge/voice-rtc',upstream='127.0.0.1:7010',
                apacheRollback=str(deploy/'apache-before.conf'))
    (deploy/'release.json').write_text(json.dumps(result,indent=2))
    print(json.dumps(result,indent=2))
except Exception:
    config.write_text(original)
    subprocess.run(['apache2ctl','configtest'],check=True)
    subprocess.run(['systemctl','reload','apache2'],check=True)
    subprocess.run(['systemctl','stop','ro-th-online-voice-rtc'])
    raise
