"""Radix Edge CLI — local job submission and monitoring."""

from __future__ import annotations

import json
from typing import Optional

import httpx
import typer
from rich.console import Console
from rich.table import Table

app = typer.Typer(name="radix-edge", help="Radix Edge Agent CLI")
console = Console()

DEFAULT_BASE_URL = "http://localhost:8080"


def _base_url() -> str:
    return DEFAULT_BASE_URL


def _get(path: str) -> dict:
    resp = httpx.get(f"{_base_url()}{path}", timeout=10)
    resp.raise_for_status()
    return resp.json()


def _post(path: str, data: dict) -> dict:
    resp = httpx.post(f"{_base_url()}{path}", json=data, timeout=10)
    resp.raise_for_status()
    return resp.json()


def _delete(path: str) -> dict:
    resp = httpx.delete(f"{_base_url()}{path}", timeout=10)
    resp.raise_for_status()
    return resp.json()


@app.command()
def submit(
    image: str = typer.Argument(..., help="Docker image to run"),
    command: Optional[str] = typer.Option(None, "--command", "-c", help="Command (JSON array)"),
    gpus: int = typer.Option(1, "--gpus", "-g", help="Number of GPUs"),
    priority: int = typer.Option(5, "--priority", "-p", help="Priority (1-10)"),
    job_type: str = typer.Option("generic", "--type", "-t", help="Job type"),
    user: str = typer.Option("default", "--user", "-u", help="User ID"),
    timeout: int = typer.Option(3600, "--timeout", help="Timeout in seconds"),
    name: Optional[str] = typer.Option(None, "--name", "-n", help="Job name"),
):
    """Submit a new job."""
    payload = {
        "image": image,
        "num_gpus": gpus,
        "priority": priority,
        "job_type": job_type,
        "user_id": user,
        "timeout_seconds": timeout,
    }
    if command:
        payload["command"] = json.loads(command)
    if name:
        payload["name"] = name

    try:
        result = _post("/v1/jobs", payload)
        console.print(f"[green]Job submitted:[/green] {result['job_id']}")
    except httpx.HTTPError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


@app.command()
def status(job_id: str = typer.Argument(..., help="Job ID")):
    """Get job status."""
    try:
        job = _get(f"/v1/jobs/{job_id}")
        table = Table(title=f"Job {job_id}")
        table.add_column("Field", style="cyan")
        table.add_column("Value")

        for key in ["status", "image", "user_id", "job_type", "priority", "num_gpus",
                     "scheduled_gpus", "created_at", "started_at", "completed_at",
                     "runtime_seconds", "exit_code", "error_message"]:
            val = job.get(key)
            if val is not None:
                table.add_row(key, str(val))

        console.print(table)
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            console.print(f"[red]Job {job_id} not found[/red]")
        else:
            console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


@app.command()
def ls(
    status_filter: Optional[str] = typer.Option(None, "--status", "-s", help="Filter by status"),
    user: Optional[str] = typer.Option(None, "--user", "-u", help="Filter by user"),
    limit: int = typer.Option(20, "--limit", "-l", help="Max results"),
):
    """List jobs."""
    params = []
    if status_filter:
        params.append(f"status={status_filter}")
    if user:
        params.append(f"user_id={user}")
    params.append(f"limit={limit}")

    query = "&".join(params)
    try:
        result = _get(f"/v1/jobs?{query}")
        jobs = result.get("jobs", [])

        if not jobs:
            console.print("[dim]No jobs found[/dim]")
            return

        table = Table(title=f"Jobs ({len(jobs)})")
        table.add_column("ID", style="cyan", no_wrap=True)
        table.add_column("Status")
        table.add_column("User")
        table.add_column("Image")
        table.add_column("GPUs", justify="right")
        table.add_column("Created")

        for j in jobs:
            status_style = {
                "queued": "yellow", "scheduled": "blue", "running": "green",
                "succeeded": "green bold", "failed": "red", "cancelled": "dim",
            }.get(j["status"], "")
            table.add_row(
                j["job_id"],
                f"[{status_style}]{j['status']}[/{status_style}]",
                j.get("user_id", ""),
                j.get("image", "")[:40],
                str(j.get("num_gpus", 1)),
                (j.get("created_at") or "")[:19],
            )

        console.print(table)
    except httpx.HTTPError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


@app.command()
def cancel(job_id: str = typer.Argument(..., help="Job ID to cancel")):
    """Cancel a job."""
    try:
        result = _delete(f"/v1/jobs/{job_id}")
        console.print(f"[yellow]Cancelled:[/yellow] {result.get('message', job_id)}")
    except httpx.HTTPStatusError as e:
        console.print(f"[red]Error:[/red] {e.response.json().get('detail', str(e))}")
        raise typer.Exit(1)


@app.command()
def gpus():
    """Show GPU status."""
    try:
        result = _get("/v1/gpus")
        gpu_list = result.get("gpus", [])

        if not gpu_list:
            console.print("[dim]No GPUs detected[/dim]")
            return

        table = Table(title=f"GPUs ({len(gpu_list)})")
        table.add_column("Idx", justify="right", style="cyan")
        table.add_column("Name")
        table.add_column("Status")
        table.add_column("Util %", justify="right")
        table.add_column("Mem Used", justify="right")
        table.add_column("Mem Total", justify="right")
        table.add_column("Temp", justify="right")
        table.add_column("Power", justify="right")
        table.add_column("Job")

        for g in gpu_list:
            status_style = {"idle": "green", "allocated": "yellow", "error": "red"}.get(g["status"], "")
            table.add_row(
                str(g["gpu_index"]),
                g.get("name", "")[:30],
                f"[{status_style}]{g['status']}[/{status_style}]",
                f"{g.get('utilization_pct', 0):.0f}",
                f"{g.get('memory_used_mb', 0)} MB",
                f"{g.get('memory_total_mb', 0)} MB",
                f"{g.get('temperature_c', 0):.0f}°C",
                f"{g.get('power_draw_w', 0):.0f}W",
                g.get("assigned_job_id") or "-",
            )

        console.print(table)
    except httpx.HTTPError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


@app.command("config")
def show_config(
    action: str = typer.Argument("show", help="Action: show or set"),
    key: Optional[str] = typer.Argument(None, help="Config key (for set)"),
    value: Optional[str] = typer.Argument(None, help="Config value (for set)"),
):
    """Show or set configuration."""
    try:
        if action == "show":
            brain = _get("/v1/config/brain")
            table = Table(title="Brain Parameters")
            table.add_column("Parameter", style="cyan")
            table.add_column("Value", justify="right")
            for k, v in brain.items():
                table.add_row(k, f"{v:.4f}" if isinstance(v, float) else str(v))
            console.print(table)
        else:
            console.print("[red]Config set not yet implemented[/red]")
    except httpx.HTTPError as e:
        console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


if __name__ == "__main__":
    app()
