"""deskclaw-client CLI — register bots, trigger tests, check results."""

from __future__ import annotations

import logging
import socket
import sys

import click

from deskclaw_client.api import DeskClawAPI


def _make_api(server: str) -> DeskClawAPI:
    return DeskClawAPI(server)


def _guess_local_ip() -> str:
    """Best-effort detection of the LAN-reachable IP of this machine."""
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception:
        return "127.0.0.1"


def _echo_ok(msg: str) -> None:
    click.echo(click.style(f"  OK  {msg}", fg="green"))


def _echo_err(msg: str) -> None:
    click.echo(click.style(f"  ERR {msg}", fg="red"), err=True)


def _echo_info(msg: str) -> None:
    click.echo(click.style(f"  ..  {msg}", fg="cyan"))


@click.group()
@click.version_option(package_name="deskclaw-client")
def cli() -> None:
    """DeskClaw Client — register your bot, run tests, check results."""


# ── register ──


@cli.command()
@click.option(
    "--server",
    required=True,
    envvar="DESKCLAW_SERVER",
    help="Exam server URL (e.g. http://192.168.1.50:8420). Env: DESKCLAW_SERVER",
)
@click.option("--name", required=True, help="Unique name for your bot.")
@click.option(
    "--url",
    required=True,
    help="Your bot's HTTP API endpoint (e.g. http://localhost:8080/v1/chat/completions).",
)
@click.option(
    "--protocol",
    type=click.Choice(["openai", "anthropic", "custom"]),
    default="openai",
    help="API protocol (default: openai).",
)
@click.option(
    "--capabilities",
    default="text_generation",
    help="Comma-separated capabilities (e.g. text_generation,tool_use,multi_turn).",
)
@click.option("--auth", "auth_token", default=None, help="Bearer auth token.")
def register(
    server: str,
    name: str,
    url: str,
    protocol: str,
    capabilities: str,
    auth_token: str | None,
) -> None:
    """Register your bot with the DeskClaw exam server."""
    api = _make_api(server)

    _echo_info(f"Connecting to exam server: {server}")
    try:
        health = api.health()
        _echo_ok(f"Server online (v{health.get('version', '?')})")
    except Exception as exc:
        _echo_err(f"Cannot reach exam server: {exc}")
        sys.exit(1)

    caps = [c.strip() for c in capabilities.split(",") if c.strip()]

    _echo_info(f"Registering bot '{name}' → {url}")
    try:
        result = api.register_adapter(
            name=name,
            url=url,
            protocol=protocol,
            capabilities=caps,
            auth_token=auth_token,
        )
        _echo_ok(f"Registered: {result['name']}")
        click.echo(f"  URL:          {result['url']}")
        click.echo(f"  Protocol:     {result['protocol']}")
        click.echo(f"  Capabilities: {', '.join(result['capabilities'])}")
        click.echo(f"  Config:       {result.get('config_path', 'N/A')}")
    except Exception as exc:
        _echo_err(f"Registration failed: {exc}")
        sys.exit(1)


# ── run ──


@cli.command()
@click.option(
    "--server",
    required=True,
    envvar="DESKCLAW_SERVER",
    help="Exam server URL. Env: DESKCLAW_SERVER",
)
@click.option("--name", required=True, help="Bot name (must be registered first).")
@click.option("--suite", default=None, help="Run only this benchmark suite.")
@click.option(
    "--wait/--no-wait",
    default=True,
    help="Wait for the run to complete (default: --wait).",
)
@click.option(
    "--timeout",
    default=1800,
    type=int,
    help="Max seconds to wait for completion (default: 1800).",
)
def run(
    server: str,
    name: str,
    suite: str | None,
    wait: bool,
    timeout: int,
) -> None:
    """Trigger a test run for your bot on the exam server."""
    api = _make_api(server)

    _echo_info(f"Triggering test run for '{name}'...")
    try:
        result = api.trigger_run(agent=name, suite=suite)
    except Exception as exc:
        _echo_err(f"Failed to trigger run: {exc}")
        sys.exit(1)

    run_id = result["run_id"]
    _echo_ok(f"Run queued: {run_id}")

    if not wait:
        click.echo(f"\n  Check status with:\n  deskclaw-client status --server {server} --run-id {run_id}")
        return

    _echo_info("Waiting for results (Ctrl+C to detach)...")

    def _on_progress(data: dict) -> None:
        progress = data.get("progress", "")
        if progress:
            _echo_info(progress)

    try:
        final = api.poll_run(
            run_id,
            interval=3.0,
            timeout=float(timeout),
            on_progress=_on_progress,
        )
    except KeyboardInterrupt:
        click.echo(f"\n  Detached. Check status later:\n  deskclaw-client status --server {server} --run-id {run_id}")
        return

    final_status = final.get("status", "unknown")
    if final_status == "completed":
        _echo_ok(f"Run completed: {run_id}")
        results = final.get("results", {})
        evaluation = results.get("evaluation", {})
        if evaluation:
            grade = evaluation.get("grade", "?")
            score = evaluation.get("adjusted_score", 0)
            click.echo(f"\n  Grade:          {grade}")
            click.echo(f"  Adjusted Score: {score:.4f}")
        else:
            click.echo("\n  (Detailed evaluation report not available)")
        click.echo(f"\n  Full report: {server}/api/v1/run/{run_id}")
    else:
        _echo_err(f"Run {final_status}: {final.get('error', 'unknown error')}")
        sys.exit(1)


# ── status ──


@cli.command()
@click.option(
    "--server",
    required=True,
    envvar="DESKCLAW_SERVER",
    help="Exam server URL. Env: DESKCLAW_SERVER",
)
@click.option("--run-id", default=None, help="Specific run ID to check.")
@click.option("--name", default=None, help="List runs for this bot name.")
def status(server: str, run_id: str | None, name: str | None) -> None:
    """Check the status of test runs."""
    api = _make_api(server)

    if run_id:
        try:
            run_data = api.get_run(run_id)
        except Exception as exc:
            _echo_err(f"Failed to fetch run: {exc}")
            sys.exit(1)

        click.echo(f"  Run ID:  {run_data['run_id']}")
        click.echo(f"  Agent:   {run_data.get('agent', '?')}")
        click.echo(f"  Status:  {run_data.get('status', '?')}")
        click.echo(f"  Created: {run_data.get('created_at', '?')}")
        if run_data.get("finished_at"):
            click.echo(f"  Finished: {run_data['finished_at']}")
        if run_data.get("progress"):
            click.echo(f"  Progress: {run_data['progress']}")
        if run_data.get("error"):
            click.echo(f"  Error:    {run_data['error']}")
        results = run_data.get("results", {})
        evaluation = results.get("evaluation", {})
        if evaluation:
            click.echo(f"  Grade:    {evaluation.get('grade', '?')}")
            click.echo(f"  Score:    {evaluation.get('adjusted_score', 0):.4f}")
        return

    try:
        runs_data = api.list_runs(agent=name)
    except Exception as exc:
        _echo_err(f"Failed to fetch runs: {exc}")
        sys.exit(1)

    runs = runs_data.get("runs", [])
    if not runs:
        click.echo("  No runs found.")
        return

    click.echo(f"  {'RUN ID':<45} {'AGENT':<20} {'STATUS':<12} {'CREATED'}")
    click.echo(f"  {'─' * 45} {'─' * 20} {'─' * 12} {'─' * 25}")
    for r in runs[:20]:
        click.echo(
            f"  {r.get('run_id', '?'):<45} "
            f"{r.get('agent', '?'):<20} "
            f"{r.get('status', '?'):<12} "
            f"{r.get('created_at', '?')[:19]}"
        )


# ── list ──


# ── serve ──


@cli.command()
@click.option(
    "--server",
    required=True,
    envvar="DESKCLAW_SERVER",
    help="Exam server URL. Env: DESKCLAW_SERVER",
)
@click.option("--name", required=True, help="Unique bot name to register.")
@click.option(
    "--bridge",
    "bridge_name",
    required=True,
    help="Bridge type (e.g. openclaw). Run 'deskclaw-client bridges' to list available bridges.",
)
@click.option(
    "--target",
    required=True,
    help="Agent native address (e.g. ws://localhost:18789).",
)
@click.option("--port", default=9090, type=int, help="Local HTTP proxy port (default: 9090).")
@click.option("--host", default="0.0.0.0", help="Local HTTP proxy bind address (default: 0.0.0.0).")
@click.option("--token", default=None, help="Agent auth token (bridge-specific).")
@click.option(
    "--capabilities",
    default="text_generation",
    help="Comma-separated capabilities.",
)
@click.option("--verbose", "-v", is_flag=True, help="Enable debug logging.")
def serve(
    server: str,
    name: str,
    bridge_name: str,
    target: str,
    port: int,
    host: str,
    token: str | None,
    capabilities: str,
    verbose: bool,
) -> None:
    """Start a local HTTP proxy that bridges a non-HTTP agent to the exam server.

    This launches an OpenAI-compatible HTTP endpoint on the local machine,
    translates requests through the specified bridge, and auto-registers
    with the DeskClaw exam server.
    """
    import uvicorn

    from deskclaw_client.bridges import get_bridge
    from deskclaw_client.serve import make_app

    logging.basicConfig(
        level=logging.DEBUG if verbose else logging.INFO,
        format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    )

    _echo_info(f"Initialising bridge '{bridge_name}' → {target}")
    try:
        bridge = get_bridge(bridge_name, target=target, token=token)
    except ValueError as exc:
        _echo_err(str(exc))
        sys.exit(1)

    local_ip = _guess_local_ip()
    proxy_url = f"http://{local_ip}:{port}/v1/chat/completions"

    api = _make_api(server)
    _echo_info(f"Registering '{name}' with exam server ({server})")
    try:
        caps = [c.strip() for c in capabilities.split(",") if c.strip()]
        result = api.register_adapter(
            name=name,
            url=proxy_url,
            protocol="openai",
            capabilities=caps,
        )
        _echo_ok(f"Registered: {result['name']} → {proxy_url}")
    except Exception as exc:
        _echo_err(f"Registration failed: {exc}")
        _echo_info("Starting proxy anyway — you can register manually later.")

    _echo_info(f"Starting HTTP proxy on {host}:{port}")
    _echo_info(f"Proxy URL: {proxy_url}")
    _echo_info("Press Ctrl+C to stop.")

    app = make_app(bridge)
    uvicorn.run(app, host=host, port=port, log_level="info")


@cli.command("bridges")
def list_bridges() -> None:
    """List available bridge types."""
    from deskclaw_client.bridges import BRIDGE_REGISTRY, _ensure_builtins_loaded

    _ensure_builtins_loaded()

    if not BRIDGE_REGISTRY:
        click.echo("  No bridges registered.")
        return

    click.echo("  Available bridges:")
    for name in sorted(BRIDGE_REGISTRY):
        cls = BRIDGE_REGISTRY[name]
        doc = (cls.__doc__ or "").strip().split("\n")[0]
        click.echo(f"    {name:<16} {doc}")


# ── list ──


@cli.command("list")
@click.option(
    "--server",
    required=True,
    envvar="DESKCLAW_SERVER",
    help="Exam server URL. Env: DESKCLAW_SERVER",
)
def list_bots(server: str) -> None:
    """List all bots registered on the exam server."""
    api = _make_api(server)

    try:
        data = api.list_adapters()
    except Exception as exc:
        _echo_err(f"Failed to fetch adapters: {exc}")
        sys.exit(1)

    adapters = data.get("adapters", [])
    if not adapters:
        click.echo("  No bots registered.")
        return

    click.echo(f"  {'NAME':<25} {'URL':<50} {'PROTOCOL':<12} {'CAPABILITIES'}")
    click.echo(f"  {'─' * 25} {'─' * 50} {'─' * 12} {'─' * 30}")
    for a in adapters:
        caps = ", ".join(a.get("capabilities", []))
        click.echo(
            f"  {a.get('name', '?'):<25} "
            f"{a.get('url', '?'):<50} "
            f"{a.get('protocol', '?'):<12} "
            f"{caps}"
        )
