#!/usr/bin/env python3
"""Subprocess-safe remote program-state sync.

Reads jupyter binding JSON, fetches program-state.jsonl via jupyter
Contents API (HTTP GET), writes to local path. Designed to be called
via asyncio.create_subprocess_exec with a hard timeout — if the pod is
unreachable, the parent kills this process cleanly.

Usage: python3 sync_remote_state.py <binding_json_path> <local_state_path>
"""
import json
import sys
import urllib.request
import urllib.error
import ssl

def main():
    if len(sys.argv) != 3:
        sys.exit(1)
    binding_path = sys.argv[1]
    local_path = sys.argv[2]

    try:
        with open(binding_path, encoding='utf-8') as f:
            data = json.load(f)
    except (OSError, json.JSONDecodeError):
        sys.exit(1)

    binding = data.get('binding', {})
    base_url = binding.get('base_url', '').rstrip('/')
    api_path = binding.get('workspace_api_path', '')
    if not base_url or not api_path:
        sys.exit(1)

    cookies_list = data.get('cookies', [])
    cookie_str = '; '.join(f"{c['name']}={c['value']}" for c in cookies_list)
    xsrf = data.get('xsrf_token', '')

    file_api_path = f"{api_path}/output/program-state.jsonl"
    url = f"{base_url}/api/contents/{file_api_path}?content=1&type=file"

    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_peer = False

    req = urllib.request.Request(url)
    req.add_header('Cookie', cookie_str)
    if xsrf:
        req.add_header('X-XSRFToken', xsrf)

    try:
        resp = urllib.request.urlopen(req, timeout=8, context=ctx)
        body = json.loads(resp.read())
    except (urllib.error.URLError, OSError, json.JSONDecodeError, TimeoutError):
        sys.exit(1)

    content = body.get('content', '')
    if not content or not content.strip():
        sys.exit(0)

    # Preserve local-only _synthetic entries
    local_synthetics = []
    try:
        with open(local_path, encoding='utf-8') as f:
            for line in f:
                if '"_synthetic"' in line:
                    try:
                        obj = json.loads(line)
                        if obj.get('_synthetic'):
                            local_synthetics.append(line.rstrip('\n'))
                    except (json.JSONDecodeError, ValueError):
                        pass
    except OSError:
        pass

    merged = content.rstrip('\n')
    if local_synthetics:
        merged += '\n' + '\n'.join(local_synthetics)
    merged += '\n'

    # Skip rewrite if unchanged
    try:
        with open(local_path, encoding='utf-8') as f:
            if f.read() == merged:
                sys.exit(0)
    except OSError:
        pass

    import os
    os.makedirs(os.path.dirname(local_path), exist_ok=True)
    with open(local_path, 'w', encoding='utf-8') as f:
        f.write(merged)


if __name__ == '__main__':
    main()
