"""Assistant commands for manta-client CLI."""

from __future__ import annotations

import asyncio
from typing import Any

import typer

from manta_client.api.agent.assistant import get_assistant_api
from manta_client.api.client import APIError
from manta_client.exitcodes import VALIDATION_ERROR, exit_code_for_api_error
from manta_client.output import (
    console,
    is_quiet,
    print_error,
    print_json,
    print_key_value,
    print_success,
    print_table,
)

app = typer.Typer(help="Assistant management")


def _format_status(status: str) -> str:
    """Format assistant status with color."""
    status_colors = {
        "creating": "[yellow]creating[/yellow]",
        "running": "[green]running[/green]",
        "idle": "[blue]idle[/blue]",
        "stopped": "[dim]stopped[/dim]",
        "failed": "[red]failed[/red]",
    }
    return status_colors.get(status, status)


def _exit_for_api_error(e: APIError) -> None:
    """Print error and exit with appropriate code."""
    print_error(e.message)
    raise typer.Exit(exit_code_for_api_error(e.code))


@app.command("create")
def create_assistant(
    name: str = typer.Option(..., "--name", "-n", help="Assistant name"),
    system_prompt: str = typer.Option(
        None, "--system-prompt", "-p", help="System prompt for the assistant"
    ),
    skill: list[str] = typer.Option(  # noqa: B008
        None, "--skill", "-s", help="Skill slug (repeatable)"
    ),
    workspace: str = typer.Option(None, "--workspace", "-w", help="Workspace name"),
    model: str = typer.Option(None, "--model", "-M", help="LLM model (e.g., claude-sonnet-4-5)"),
    idle_timeout: int = typer.Option(None, "--idle-timeout", help="Idle timeout in seconds"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Create and start a new persistent assistant."""

    async def _create():
        workspace_id = None
        if workspace:
            from manta_client.api.agent.workspace import get_workspace_api

            ws_api = get_workspace_api()
            ws = await ws_api.get_workspace_by_name(workspace)
            workspace_id = ws.get("id")
            if not workspace_id:
                raise ValueError(f"Workspace '{workspace}' not found")

        api = get_assistant_api()
        return await api.create_assistant(
            name,
            system_prompt=system_prompt,
            skill_slugs=skill if skill else None,
            workspace_id=workspace_id,
            model=model,
            idle_timeout=idle_timeout,
        )

    try:
        result = asyncio.run(_create())
    except APIError as e:
        _exit_for_api_error(e)
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(VALIDATION_ERROR) from None

    assistant_id = result.get("assistant_id", "")

    if is_quiet():
        print(assistant_id)
        return

    if json_output:
        print_json(result)
        return

    print_success(f"Assistant created: {assistant_id}")
    console.print(f"Name: {result.get('name')}")
    console.print(f"Status: {_format_status(result.get('status', 'creating'))}")


@app.command("list")
def list_assistants(
    limit: int = typer.Option(20, "--limit", "-l", help="Max number to show"),
    status: str | None = typer.Option(None, "--status", "-s", help="Filter by status"),
    all_users: bool = typer.Option(False, "--all", "-a", help="Show all users"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """List assistants."""

    async def _list():
        api = get_assistant_api()
        user_id = None
        if not all_users:
            from manta_client.config import config_manager

            config = config_manager.load_config()
            user_id = config.user_id or None
        return await api.list_assistants(limit=limit, status=status, user_id=user_id)

    try:
        result = asyncio.run(_list())
    except APIError as e:
        _exit_for_api_error(e)

    items = result.get("items", [])
    total = result.get("total", 0)

    if json_output:
        print_json(result)
        return

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

    if is_quiet():
        for a in items:
            print(a.get("assistant_id", ""))
        return

    for a in items:
        a["status"] = _format_status(a.get("status", ""))

    columns = [
        ("assistant_id", "Assistant ID"),
        ("name", "Name"),
        ("status", "Status"),
        ("message_count", "Messages"),
        ("created_at", "Created"),
    ]
    print_table(items, columns=columns, title=f"Assistants ({total})", id_field="assistant_id")


@app.command("info")
def assistant_info(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show assistant details."""

    async def _get():
        api = get_assistant_api()
        return await api.get_assistant(assistant_id)

    try:
        result = asyncio.run(_get())
    except APIError as e:
        _exit_for_api_error(e)

    if json_output:
        print_json(result)
        return

    if is_quiet():
        print(result.get("status", ""))
        return

    data: dict[str, Any] = {
        "Assistant ID": result.get("assistant_id"),
        "Name": result.get("name"),
        "Status": result.get("status"),
        "Model": result.get("model") or "-",
        "Messages": result.get("message_count", 0),
        "Idle Timeout": f"{result.get('idle_timeout', 1800)}s",
        "Last Active": result.get("last_active_at") or "-",
        "Created At": result.get("created_at") or "-",
    }
    print_key_value(data, title="Assistant Details")

    error = result.get("error")
    if error:
        console.print(f"\n[red]Error: {error}[/red]")


@app.command("send")
def send_message(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
    message: str = typer.Option(..., "--message", "-m", help="Message to send"),
    follow: bool = typer.Option(True, "--follow/--no-follow", "-f", help="Follow response stream"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Send a message to the assistant and stream the response."""

    async def _send_and_stream():
        api = get_assistant_api()

        # Send message
        msg = await api.send_message(assistant_id, message)

        if json_output and not follow:
            print_json(msg)
            return

        if not follow:
            if is_quiet():
                print("sent")
            else:
                print_success("Message sent")
            return

        # Stream response
        async for event in api.stream_assistant(assistant_id):
            event_type = event.get("event_type", "")

            if event_type == "content_delta":
                text = event.get("data", {}).get("text", "")
                if text:
                    print(text, end="", flush=True)

            elif event_type == "tool_use":
                tool = event.get("data", {}).get("tool", "")
                if not is_quiet():
                    console.print(f"\n[cyan]Tool: {tool}[/cyan]", end="")

            elif event_type == "message_complete":
                data = event.get("data", {})
                content = data.get("content", "")
                if json_output:
                    print_json(data)
                elif content and not is_quiet():
                    # Content already streamed via deltas
                    print()  # Newline after streaming
                break

            elif event_type == "error":
                error = event.get("data", {}).get("error", "Unknown error")
                if not is_quiet():
                    console.print(f"\n[red]Error: {error}[/red]")
                break

    try:
        asyncio.run(_send_and_stream())
    except APIError as e:
        _exit_for_api_error(e)


@app.command("messages")
def list_messages(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
    limit: int = typer.Option(50, "--limit", "-l", help="Max messages"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show message history for an assistant."""

    async def _list():
        api = get_assistant_api()
        return await api.get_messages(assistant_id, limit=limit)

    try:
        result = asyncio.run(_list())
    except APIError as e:
        _exit_for_api_error(e)

    items = result.get("items", [])

    if json_output:
        print_json(result)
        return

    if not items:
        if not is_quiet():
            console.print("[dim]No messages.[/dim]")
        return

    for msg in items:
        role = msg.get("role", "")
        content = msg.get("content", "")
        if is_quiet():
            print(f"{role}: {content[:200]}")
        else:
            role_style = "[bold blue]" if role == "user" else "[bold green]"
            console.print(f"{role_style}{role}:[/] {content}")


@app.command("stop")
def stop_assistant(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
) -> None:
    """Stop and delete an assistant."""

    async def _stop():
        api = get_assistant_api()
        return await api.delete_assistant(assistant_id)

    try:
        asyncio.run(_stop())
        if is_quiet():
            print("stopped")
        else:
            print_success(f"Assistant {assistant_id} stopped.")
    except APIError as e:
        _exit_for_api_error(e)


@app.command("suspend")
def suspend_assistant(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
) -> None:
    """Suspend an assistant (scale to 0)."""

    async def _suspend():
        api = get_assistant_api()
        return await api.suspend_assistant(assistant_id)

    try:
        asyncio.run(_suspend())
        if is_quiet():
            print("idle")
        else:
            print_success(f"Assistant {assistant_id} suspended.")
    except APIError as e:
        _exit_for_api_error(e)


@app.command("resume")
def resume_assistant(
    assistant_id: str = typer.Argument(..., help="Assistant ID"),
) -> None:
    """Resume a suspended assistant."""

    async def _resume():
        api = get_assistant_api()
        return await api.resume_assistant(assistant_id)

    try:
        asyncio.run(_resume())
        if is_quiet():
            print("running")
        else:
            print_success(f"Assistant {assistant_id} resumed.")
    except APIError as e:
        _exit_for_api_error(e)
