"""OpenClaw configuration and service management."""

import json
import os
import time

from .const import API_KEY_PLACEHOLDER
from .output import GatewayTimeoutError
from .sandbox import SandboxManager
from .utils import print_error, print_info, print_success

GATEWAY_PORT = 18789
OPENCLAW_CONFIG_PATH = "/home/user/.openclaw/config.json"


def load_openclaw_config_template() -> dict:
    """Load openclaw.example.json as config template."""
    example_path = os.path.join(os.path.dirname(__file__), "openclaw.example.json")
    with open(example_path) as f:
        return json.load(f)


def generate_openclaw_config(api_key: str, gateway_token: str) -> dict:
    """Generate OpenClaw configuration by injecting API key and gateway token."""
    config = load_openclaw_config_template()

    # Replace placeholder API key in all providers
    for provider in config.get("models", {}).get("providers", {}).values():
        if provider.get("apiKey") == API_KEY_PLACEHOLDER:
            provider["apiKey"] = api_key

    # Set gateway config — use token auth so Control UI can auto-authenticate via URL
    config.setdefault("gateway", {})
    config["gateway"]["mode"] = "local"
    config["gateway"]["auth"] = {"mode": "token", "token": gateway_token}
    # Allow host-header origin fallback and disable device pairing for remote sandbox access
    config["gateway"]["controlUi"] = {
        "dangerouslyAllowHostHeaderOriginFallback": True,
        "dangerouslyDisableDeviceAuth": True,
    }

    return config


def configure_openclaw(manager: SandboxManager, api_key: str, gateway_token: str):
    """Write OpenClaw configuration to the sandbox."""
    config = generate_openclaw_config(api_key, gateway_token)
    config_content = json.dumps(config, indent=2)

    # Ensure config directory exists
    manager.run_command("mkdir -p /home/user/.openclaw", timeout=10)

    print_info("Writing OpenClaw configuration to sandbox...")
    manager.write_file(OPENCLAW_CONFIG_PATH, config_content)
    print_success("OpenClaw configuration written")

    # Start gateway in background via nohup so process persists
    print_info("Starting OpenClaw Gateway...")
    manager.run_command(
        "nohup bash -c 'OPENCLAW_CONFIG_PATH={config} openclaw gateway --port {port} --bind lan'"
        " > /tmp/gateway.log 2>&1 &".format(config=OPENCLAW_CONFIG_PATH, port=GATEWAY_PORT),
        timeout=10,
    )

    # Wait for gateway to be ready — poll every 1s, up to 120 checks (~120s max).
    max_checks = 120

    for i in range(max_checks):
        result = manager.run_command(
            'curl -s --max-time 2 -o /dev/null -w "%{{http_code}}" http://localhost:{port}/ 2>/dev/null; echo'.format(
                port=GATEWAY_PORT
            ),
            timeout=10,
        )
        if result and result.stdout and result.stdout.strip() == "200":
            print_success("OpenClaw Gateway is listening on port {port}".format(port=GATEWAY_PORT))
            _start_device_auto_approve(manager)
            return
        print_info("  Waiting for Gateway to start ({i}/{total})...".format(
            i=i + 1, total=max_checks,
        ))
        time.sleep(1)

    # Print gateway log on failure for debugging
    log_result = manager.run_command("tail -30 /tmp/gateway.log 2>&1 || true", timeout=5)
    log_text = ""
    if log_result and log_result.stdout and log_result.stdout.strip():
        log_text = log_result.stdout.strip()
        print_error("Gateway log:\n{log}".format(log=log_text))
    raise GatewayTimeoutError(
        "Gateway did not start in time. Check sandbox logs." +
        (f"\n{log_text}" if log_text else "")
    )


_DEVICE_AUTO_APPROVE_TEMPLATE = (
    "#!/bin/bash\n"
    "# Auto-approve device pairing requests for remote sandbox access.\n"
    "# The sandbox is already protected by gateway token auth.\n"
    "export OPENCLAW_CONFIG_PATH=\"{config}\"\n"
    "while true; do\n"
    "  openclaw devices list --json 2>/dev/null"
    " | node -e 'let d=\"\";process.stdin.on(\"data\",c=>d+=c);"
    "process.stdin.on(\"end\",()=>{{try{{JSON.parse(d).pending"
    ".forEach(p=>console.log(p.requestId))}}catch(e){{}}}})'  "
    " | while read -r rid; do\n"
    "    openclaw devices approve \"$rid\" 2>/dev/null\n"
    "  done\n"
    "  sleep 2\n"
    "done\n"
)

DEVICE_AUTO_APPROVE_PATH = "/tmp/device-auto-approve.sh"


def _start_device_auto_approve(manager: SandboxManager):
    """Start a background daemon that auto-approves device pairing requests.

    OpenClaw requires device pairing for remote connections (TUI, new browsers).
    This daemon polls for pending requests and approves them automatically,
    since the sandbox is already protected by gateway token auth.
    """
    script = _DEVICE_AUTO_APPROVE_TEMPLATE.format(config=OPENCLAW_CONFIG_PATH)
    manager.write_file(DEVICE_AUTO_APPROVE_PATH, script)
    manager.run_command(
        "nohup bash {path} > /tmp/device-auto-approve.log 2>&1 &".format(path=DEVICE_AUTO_APPROVE_PATH),
        timeout=10,
    )
    print_success("Device auto-approval daemon started")


def get_gateway_token(manager: SandboxManager) -> str:
    """Read the gateway token from the sandbox's OpenClaw config."""
    content = manager.read_file(OPENCLAW_CONFIG_PATH)
    if content:
        try:
            config = json.loads(content)
            return config.get("gateway", {}).get("auth", {}).get("token", "")
        except (json.JSONDecodeError, AttributeError):
            pass
    return ""


def get_public_urls(manager: SandboxManager) -> dict:
    """Get public access URLs for Gateway and Web UI."""
    host = manager.sandbox.get_host(GATEWAY_PORT)
    return {
        "gateway_ws": "wss://{host}".format(host=host),
        "webui": "https://{host}".format(host=host),
    }
