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

from __future__ import annotations

import asyncio
from typing import Any

import typer

from manta_client.api.agent.cluster import get_cluster_api
from manta_client.api.client import APIError
from manta_client.exitcodes import 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="Cluster management")


@app.command("list")
def list_clusters(
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """List available clusters."""

    async def _list():
        api = get_cluster_api()
        return await api.list_clusters()

    try:
        result = asyncio.run(_list())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    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 clusters found.[/dim]")
        return

    if is_quiet():
        for item in items:
            print(item.get("name", ""))
        return

    columns = [
        ("id", "ID"),
        ("name", "Name"),
        ("display_name", "Display Name"),
        ("api_server", "API Server"),
        ("status", "Status"),
    ]
    print_table(items, columns=columns, title=f"Clusters ({total})")


@app.command("info")
def cluster_info(
    name: str = typer.Argument(..., help="Cluster name"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show cluster details by name."""

    async def _get():
        api = get_cluster_api()
        return await api.get_cluster_by_name(name)

    try:
        cluster = asyncio.run(_get())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(cluster)
        return

    if is_quiet():
        print(cluster.get("name", ""))
        return

    data: dict[str, Any] = {
        "ID": cluster.get("id"),
        "Name": cluster.get("name"),
        "Display Name": cluster.get("display_name"),
        "API Server": cluster.get("api_server") or "-",
        "Kubeconfig Secret": cluster.get("admin_kubeconfig_secret") or "-",
        "Status": cluster.get("status"),
        "Description": cluster.get("description") or "-",
    }
    print_key_value(data, title="Cluster Details")


@app.command("download-kubeconfig")
def download_kubeconfig(
    name: str = typer.Argument(..., help="Cluster name"),
    output: str = typer.Option(None, "--output", "-o", help="Save kubeconfig to file path"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Download your kubeconfig for a cluster. Auto-provisions on first use."""

    async def _download():
        api = get_cluster_api()
        return await api.download_kubeconfig(name)

    try:
        result = asyncio.run(_download())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
        return

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

    if output:
        from pathlib import Path

        path = Path(output).expanduser()
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(kubeconfig)
        path.chmod(0o600)
        if not is_quiet():
            print_success(f"Kubeconfig saved to {path}")
            console.print(f"\n  export KUBECONFIG={path}\n")
    else:
        # Print raw kubeconfig to stdout (pipe-friendly)
        print(kubeconfig, end="")


# --- Admin commands (require superuser) ---


@app.command("create")
def create_cluster(
    name: str = typer.Option(..., "--name", "-n", help="Unique cluster name (e.g., idc, gcp)"),
    display_name: str = typer.Option(..., "--display-name", "-D", help="Human-readable name"),
    description: str = typer.Option(None, "--description", "-d", help="Cluster description"),
    api_server: str = typer.Option(None, "--api-server", help="K8s API server URL"),
    kubeconfig_secret: str = typer.Option(
        None, "--kubeconfig-secret", "-k", help="K8s Secret name storing admin kubeconfig"
    ),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Register a new cluster (admin only)."""

    async def _create():
        data: dict[str, Any] = {"name": name, "display_name": display_name}
        if description:
            data["description"] = description
        if api_server:
            data["api_server"] = api_server
        if kubeconfig_secret:
            data["admin_kubeconfig_secret"] = kubeconfig_secret
        api = get_cluster_api()
        return await api.create_cluster(data)

    try:
        result = asyncio.run(_create())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("name", ""))
    else:
        print_success(f"Cluster created: {result.get('name')} (ID: {result.get('id')})")


@app.command("update")
def update_cluster(
    name: str = typer.Argument(..., help="Cluster name"),
    display_name: str = typer.Option(None, "--display-name", "-D", help="Display name"),
    description: str = typer.Option(None, "--description", "-d", help="Description"),
    api_server: str = typer.Option(None, "--api-server", help="K8s API server URL"),
    kubeconfig_secret: str = typer.Option(
        None, "--kubeconfig-secret", "-k", help="K8s Secret name for admin kubeconfig"
    ),
    status: str = typer.Option(None, "--status", help="Status (active/inactive)"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Update a cluster by name (admin only)."""

    async def _update():
        api = get_cluster_api()
        cluster = await api.get_cluster_by_name(name)
        cluster_id = cluster.get("id")
        if not cluster_id:
            raise ValueError(f"Cluster '{name}' not found")

        data: dict[str, Any] = {}
        if display_name is not None:
            data["display_name"] = display_name
        if description is not None:
            data["description"] = description
        if api_server is not None:
            data["api_server"] = api_server
        if kubeconfig_secret is not None:
            data["admin_kubeconfig_secret"] = kubeconfig_secret
        if status is not None:
            data["status"] = status
        return await api.update_cluster(cluster_id, data)

    try:
        result = asyncio.run(_update())
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(1) from None

    if json_output:
        print_json(result)
    elif is_quiet():
        print(result.get("name", ""))
    else:
        print_success(f"Cluster updated: {result.get('name')}")


@app.command("delete")
def delete_cluster(
    name: str = typer.Argument(..., help="Cluster name"),
) -> None:
    """Delete a cluster by name (admin only)."""

    async def _delete():
        api = get_cluster_api()
        cluster = await api.get_cluster_by_name(name)
        cluster_id = cluster.get("id")
        if not cluster_id:
            raise ValueError(f"Cluster '{name}' not found")
        return await api.delete_cluster(cluster_id)

    try:
        asyncio.run(_delete())
        if is_quiet():
            print("deleted")
        else:
            print_success(f"Cluster '{name}' deleted.")
    except APIError as e:
        print_error(e.message)
        raise typer.Exit(exit_code_for_api_error(e.code)) from None
    except ValueError as e:
        print_error(str(e))
        raise typer.Exit(1) from None
