"""Click wrappers: tools group — tool registry + job queue CLI."""
from __future__ import annotations

import click

from proxym.cli._groups._shared import (
    make_args as _make_args,
    api_json_cmd,
    api_json_arg_cmd,
)
from proxym.cli._client import print_json_if_yaml


@click.group(name="tools")
def tools():
    """Manage AI development tools and job queue."""
    pass


@tools.command(name="list")
@click.option("--category", default=None, help="Filter: ide, agent_cli, browser")
@click.option("--available", is_flag=True, help="Only show tools with an available host or docker-backed instance")
@click.pass_context
def tools_list(ctx: click.Context, category: str | None, available: bool):
    """List registered tools."""
    from proxym.cli._client import make_client
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)
    params = {}
    if category:
        params["category"] = category
    if available:
        params["available_only"] = "true"
    r = c.get("/dashboard/tools/", params=params)
    data = r.json()
    if print_json_if_yaml(args, data):
        return
    for t in data.get("tools", []):
        icon = "\033[32m\u2713\033[0m" if t.get("available") else "\033[31m\u2717\033[0m"
        click.echo(f"  {icon}  {t['name']:<15s}  {t.get('category', ''):<10s}  {t.get('description', '')}")


def _resolve_dispatch_args(client, ticket_id: str, tool: str, project_dir: str) -> tuple[str, str]:
    """Auto-resolve tool and project_dir from ticket/project if not given explicitly."""
    if tool and project_dir:
        return tool, project_dir
    try:
        r = client.get(f"/dashboard/tickets/{ticket_id}")
        if r.status_code != 200:
            return tool, project_dir
        tkt = r.json()
        # Resolve tool: explicit > ticket's assigned_tool > project default_tool
        if not tool:
            assigned = tkt.get("assigned_tool") or {}
            tool = assigned.get("tool", "")
        if not tool and tkt.get("project_id"):
            try:
                rp = client.get(f"/dashboard/projects/{tkt['project_id']}")
                if rp.status_code == 200:
                    proj = rp.json()
                    tool = tool or proj.get("default_tool", "")
                    if not project_dir:
                        project_dir = proj.get("local_path") or proj.get("source_path") or ""
            except Exception:
                pass
    except Exception:
        pass
    return tool, project_dir


@tools.command(name="dispatch")
@click.argument("ticket", required=False, default=None)
@click.option("--ticket", "ticket_opt", default=None, help="Ticket ID (alternative to positional arg)", hidden=True)
@click.option("--tool", default=None, help="Tool name (auto-resolved from ticket if omitted)")
@click.option("--mode", default="", help="Agent mode (code, architect, debug, ask)")
@click.option("--model", default="", help="Model alias or full name")
@click.option("--project-dir", default="", help="Project directory (auto-resolved if omitted)")
@click.option("--dry-run", is_flag=True, help="Validate without dispatching (pre-flight check)")
@click.pass_context
def tools_dispatch(ctx: click.Context, ticket: str | None, ticket_opt: str | None,
                  tool: str | None, mode: str, model: str, project_dir: str, dry_run: bool):
    """Dispatch a tool to work on a ticket.

    \b
    Tool and project-dir are auto-resolved from ticket/project if omitted.
    Examples:
      proxym tools dispatch TKT-XXX                     # auto-resolve everything
      proxym tools dispatch TKT-XXX --tool claude-code  # override tool
      proxym tools dispatch TKT-XXX --dry-run           # validate only
    """
    from proxym.cli._client import make_client, print_json
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)

    ticket_id = ticket or ticket_opt
    if not ticket_id:
        click.echo("  Error: ticket ID is required (positional or --ticket).")
        ctx.exit(1)
        return

    # Auto-resolve tool and project_dir from ticket metadata
    resolved_tool, resolved_dir = _resolve_dispatch_args(c, ticket_id, tool or "", project_dir)
    if not resolved_tool:
        click.echo(f"  Error: could not determine tool for {ticket_id}. Use --tool to specify.")
        ctx.exit(1)
        return

    if dry_run:
        r = c.post("/dashboard/tools/dispatch/dry-run", json={
            "ticket_id": ticket_id, "tool": resolved_tool, "mode": mode, "model": model,
            "project_dir": resolved_dir,
        })
        data = r.json()
        click.echo(f"\n  Dry-run: {ticket_id} → {resolved_tool}")
        click.echo(f"  Can dispatch: {'✓ Yes' if data.get('can_dispatch') else '✗ No'}")
        if data.get('errors'):
            click.echo(f"\n  {click.style('Errors:', fg='red')}")
            for err in data['errors']:
                click.echo(f"    ✗ {err}")
        if data.get('warnings'):
            click.echo(f"\n  {click.style('Warnings:', fg='yellow')}")
            for warn in data['warnings']:
                click.echo(f"    ⚠ {warn}")
        if data.get('project_dir'):
            click.echo(f"\n  Project dir: {data['project_dir']}")
        if data.get('next_steps'):
            click.echo(f"\n  {click.style('Next steps:', fg='cyan')}")
            for step in data['next_steps']:
                click.echo(f"    → {step}")
        click.echo()
    else:
        r = c.post("/dashboard/tools/dispatch", json={
            "ticket_id": ticket_id, "tool": resolved_tool, "mode": mode, "model": model,
            "project_dir": resolved_dir,
        })
        data = r.json()
        if print_json_if_yaml(args, data):
            return
        job = data.get("job")
        msg = data.get("message", "")
        if job:
            click.echo(f"  ✅ {msg}")
            click.echo(f"     Job: {job['id']}  Tool: {job.get('tool', resolved_tool)}  Status: {job.get('status', '?')}")
            if job.get("project_dir"):
                click.echo(f"     Dir: {job['project_dir']}")
        elif data.get("error"):
            click.echo(f"  ✗ {data['error']}")
        else:
            click.echo(f"  ✅ {msg or 'Dispatched'}")
        if not tool:
            click.echo(f"     (tool auto-resolved: {resolved_tool})")
        if not project_dir and resolved_dir:
            click.echo(f"     (dir auto-resolved: {resolved_dir})")



@tools.command(name="queue")
@click.pass_context
def tools_queue(ctx: click.Context):
    """Show job queue status."""
    from proxym.cli._client import make_client
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)
    r = c.get("/dashboard/tools/queue")
    data = r.json()
    if print_json_if_yaml(args, data):
        return
    click.echo(f"  Queue: {data.get('queue_size', 0)} pending  |  Total: {data.get('total_jobs', 0)}")
    click.echo(f"  Executor: {'running' if data.get('running') else 'stopped'}")
    for s, count in data.get("by_status", {}).items():
        click.echo(f"    {s}: {count}")


@tools.command(name="jobs")
@click.option("--status", default=None, help="Filter: queued, running, done, failed, cancelled")
@click.option("--limit", default=20, type=int, help="Max jobs to show")
@click.pass_context
def tools_jobs(ctx: click.Context, status: str | None, limit: int):
    """List jobs."""
    from proxym.cli._client import make_client
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)
    params = {"limit": limit}
    if status:
        params["status"] = status
    r = c.get("/dashboard/tools/queue/jobs", params=params)
    data = r.json()
    if print_json_if_yaml(args, data):
        return
    for j in data.get("jobs", []):
        st = j.get("status", "?")
        click.echo(f"  {j['id']}  {j.get('ticket_id', ''):<12s}  {j.get('tool', ''):<14s}  {st}")


@tools.command(name="status")
@click.pass_context
def tools_status(ctx: click.Context):
    """Combined tool dashboard: availability, model, job stats.

    \b
    Shows a single table with each tool's status, default model,
    job count, success rate, and average duration.
    """
    from proxym.cli._client import make_client
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)

    # 1. Tool list (registry)
    try:
        r_tools = c.get("/dashboard/tools/")
        tool_list = r_tools.json().get("tools", [])
    except Exception:
        tool_list = []

    # 2. Readiness snapshot (fast, from orchestrator cache)
    readiness_map: dict[str, dict] = {}
    try:
        r_ready = c.get("/dashboard/tools/readiness")
        for t in r_ready.json().get("tools", []):
            readiness_map[t.get("name", "")] = t
    except Exception:
        pass

    # 3. Job stats (all jobs, aggregate per tool)
    job_stats: dict[str, dict] = {}
    try:
        r_jobs = c.get("/dashboard/tools/queue/jobs", params={"limit": 200})
        for j in r_jobs.json().get("jobs", []):
            tool_name = j.get("tool", "?")
            st = job_stats.setdefault(tool_name, {"total": 0, "done": 0, "failed": 0, "dur_sum": 0.0})
            st["total"] += 1
            if j.get("status") == "done":
                st["done"] += 1
                st["dur_sum"] += j.get("duration_s", 0)
            elif j.get("status") == "failed":
                st["failed"] += 1
    except Exception:
        pass

    if not tool_list:
        click.echo("  No tools found. Is the server running?")
        return

    # Build table
    click.echo(f"\n  {'Tool':<16s} {'Status':<10s} {'Model':<14s} {'Jobs':>5s} {'Pass':>6s} {'Avg':>7s}")
    click.echo(f"  {'─' * 16} {'─' * 10} {'─' * 14} {'─' * 5} {'─' * 6} {'─' * 7}")

    for t in tool_list:
        name = t.get("name", "?")
        available = t.get("available", False)
        readiness = readiness_map.get(name, {})
        r_status = readiness.get("status", "ok" if available else "down")

        if r_status == "ok":
            status_str = "\033[32m✓ ready\033[0m "
        elif r_status == "degraded":
            status_str = "\033[33m◐ degr.\033[0m"
        else:
            status_str = "\033[31m✗ down\033[0m "

        model = t.get("default_model", "") or "—"
        if len(model) > 13:
            model = model[:12] + "…"

        stats = job_stats.get(name, {})
        total = stats.get("total", 0)
        done = stats.get("done", 0)
        failed = stats.get("failed", 0)
        dur_sum = stats.get("dur_sum", 0.0)

        jobs_str = str(total) if total else "—"
        if total > 0:
            rate = done / (done + failed) * 100 if (done + failed) > 0 else 0
            pass_str = f"{rate:.0f}%"
        else:
            pass_str = "—"
        avg_str = f"{dur_sum / done:.0f}s" if done > 0 else "—"

        click.echo(f"  {name:<16s} {status_str} {model:<14s} {jobs_str:>5s} {pass_str:>6s} {avg_str:>7s}")

    click.echo()


@tools.command(name="set-model")
@click.argument("tool_name")
@click.argument("model")
@click.pass_context
def tools_set_model(ctx: click.Context, tool_name: str, model: str):
    """Set the default LLM model for a tool.

    \b
    Examples:
      proxym tools set-model aider balanced
      proxym tools set-model claude-code premium
      proxym tools set-model roo-code google/gemini-2.5-flash
    """
    from proxym.cli._client import make_client, print_json
    args = _make_args(ctx)
    c = make_client(args.proxy, args.key)
    r = c.put(f"/dashboard/tools/{tool_name}", json={"default_model": model})
    if r.status_code == 404:
        click.echo(f"  Tool '{tool_name}' not found.")
        return
    data = r.json()
    click.echo(f"  ✓ {tool_name} → default_model = {data.get('default_model', model)}")


# ── Simple API passthrough commands ──────────────────────────

for _name, _method, _path_tpl, _help in [
    ("show",   "get",  "/dashboard/tools/{tool_name}",              "Show details for a specific tool."),
    ("job",    "get",  "/dashboard/tools/queue/jobs/{job_id}",      "Show details for a specific job."),
    ("cancel", "post", "/dashboard/tools/queue/jobs/{job_id}/cancel", "Cancel a queued job."),
    ("retry",  "post", "/dashboard/tools/queue/jobs/{job_id}/retry",  "Retry a failed or cancelled job."),
    ("repair", "post", "/dashboard/tools/queue/jobs/{job_id}/repair", "Run diagnosis for a failed job and print suggestions."),
]:
    _arg = "tool_name" if "tool_name" in _path_tpl else "job_id"
    tools.add_command(api_json_arg_cmd(_name, _method, _path_tpl, _help, arg_name=_arg))

for _name, _method, _path, _help in [
    ("start", "post", "/dashboard/tools/queue/start", "Start the background executor."),
    ("stop",  "post", "/dashboard/tools/queue/stop",  "Stop the background executor."),
]:
    tools.add_command(api_json_cmd(_name, _method, _path, _help))
