#!/usr/bin/env python3
import argparse
import json
import os
import shutil
import subprocess
import sys
import time
import urllib.error
import urllib.request


def load_config():
    candidates = [
        os.environ.get("OPENCLAW_CONFIG"),
        "/opt/openclaw/.openclaw/openclaw.json",
        os.path.expanduser("~/.openclaw/openclaw.json"),
    ]
    for path in candidates:
        if path and os.path.exists(path):
            with open(path, "r", encoding="utf-8") as f:
                return json.load(f)
    raise RuntimeError("openclaw config not found")


def resolve_provider(cfg):
    providers = cfg.get("models", {}).get("providers", {}) or {}
    if "clawkai" in providers:
        provider = providers["clawkai"]
    elif providers:
        provider = next(iter(providers.values()))
    else:
        raise RuntimeError("no providers configured")
    base_url = provider.get("baseUrl") or provider.get("base_url")
    api_key = provider.get("apiKey") or provider.get("api_key")
    if not base_url or not api_key:
        raise RuntimeError("provider baseUrl or apiKey missing")
    return base_url.rstrip("/"), api_key


def build_url(base_url, path):
    base = base_url.rstrip("/")
    if base.endswith("/v1"):
        return f"{base}{path}"
    return f"{base}/v1{path}"


def request_json(url, api_key, payload):
    data = json.dumps(payload).encode("utf-8")
    req = urllib.request.Request(
        url,
        data=data,
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {api_key}",
            "User-Agent": "curl/8.5.0",
        },
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=60) as resp:
            body = resp.read()
    except urllib.error.HTTPError as err:
        detail = err.read().decode("utf-8", errors="ignore")
        raise RuntimeError(f"domain request failed: {err.code} {detail}") from err
    return json.loads(body.decode("utf-8"))


def run(cmd, check=True):
    result = subprocess.run(
        cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
    )
    if check and result.returncode != 0:
        raise RuntimeError(
            f"{' '.join(cmd)} failed: {(result.stderr or result.stdout).strip()}"
        )
    return result


def wait_for_dns(domain, attempts=60, delay=10):
    if not shutil.which("getent"):
        return False
    for _ in range(attempts):
        res = subprocess.run(
            ["getent", "hosts", domain],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
        if res.returncode == 0:
            return True
        time.sleep(delay)
    return False


def write_nginx_config(domain, port):
    safe_name = domain.replace(".", "_")
    conf_path = f"/etc/nginx/sites-available/clawkai-site-{safe_name}.conf"
    enabled_path = f"/etc/nginx/sites-enabled/clawkai-site-{safe_name}.conf"
    conf = f"""server {{
  listen 80;
  server_name {domain};

  location / {{
    proxy_pass http://127.0.0.1:{port};
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 3600;
    proxy_send_timeout 3600;
    proxy_buffering off;
  }}
}}
"""
    with open(conf_path, "w", encoding="utf-8") as f:
        f.write(conf)
    if os.path.islink(enabled_path) or os.path.exists(enabled_path):
        os.remove(enabled_path)
    os.symlink(conf_path, enabled_path)
    default_path = "/etc/nginx/sites-enabled/default"
    if os.path.exists(default_path):
        os.remove(default_path)
    return conf_path


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--subdomain", required=True)
    parser.add_argument("--port", type=int, default=3000)
    parser.add_argument("--skip-certbot", action="store_true")
    parser.add_argument("--skip-dns-wait", action="store_true")
    args = parser.parse_args()

    if os.geteuid() != 0:
        raise RuntimeError("This script must run as root (sudo).")
    if not shutil.which("nginx"):
        raise RuntimeError("nginx is not installed.")
    if not shutil.which("certbot") and not args.skip_certbot:
        raise RuntimeError("certbot is not installed.")

    cfg = load_config()
    base_url, api_key = resolve_provider(cfg)
    url = build_url(base_url, "/websites/configure-domain")
    payload = request_json(url, api_key, {"subdomain": args.subdomain})

    domain = payload.get("domain") or payload.get("full_domain") or ""
    if not domain:
        raise RuntimeError("domain response missing domain")

    conf_path = write_nginx_config(domain, args.port)
    run(["nginx", "-t"])
    if shutil.which("systemctl"):
        run(["systemctl", "enable", "--now", "nginx"], check=False)
        run(["systemctl", "reload", "nginx"], check=False)

    https_ok = False
    if not args.skip_certbot:
        if not args.skip_dns_wait:
            wait_for_dns(domain)
        cert_args = [
            "certbot",
            "--nginx",
            "-d",
            domain,
            "--agree-tos",
            "--non-interactive",
            "--redirect",
        ]
        for _ in range(10):
            try:
                run(cert_args)
                https_ok = True
                break
            except Exception:
                time.sleep(30)

    print(
        json.dumps(
            {
                "domain": domain,
                "subdomain": payload.get("subdomain") or "",
                "nginx_conf": conf_path,
                "https": https_ok,
            }
        )
    )


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        sys.stderr.write(str(exc) + "\\n")
        sys.exit(1)
