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

from __future__ import annotations

import asyncio
from typing import Any

import typer

from manta_client.api.agent.resource import get_resource_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="Resource lifecycle management")


@app.command("list")
def list_resources(
    status: str = typer.Option(None, "--status", "-s", help="Filter by status"),
    limit: int = typer.Option(20, "--limit", "-l", help="Max results"),
    no_refresh: bool = typer.Option(False, "--no-refresh", help="Skip K8s scan before listing"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """List managed resources (Milvus instances with lease info).

    By default, scans your K8s namespaces first to discover new resources.
    Use --no-refresh to skip the scan and show cached results only.
    """

    async def _list():
        api = get_resource_api()
        return await api.list_resources(status=status, limit=limit, refresh=not no_refresh)

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

    if is_quiet():
        for item in items:
            print(f"{item.get('id')}\t{item.get('resource_name')}\t{item.get('status')}")
        return

    columns = [
        ("id", "ID"),
        ("resource_name", "Name"),
        ("namespace", "Namespace"),
        ("status", "Status"),
        ("expires_at", "Expires At"),
        ("lease_hours", "Lease (h)"),
        ("username", "Owner"),
    ]
    print_table(items, columns=columns, title=f"Managed Resources ({total})")


@app.command("info")
def resource_info(
    pk: int = typer.Argument(..., help="Resource ID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Show resource details."""

    async def _get():
        api = get_resource_api()
        return await api.get_resource(pk)

    try:
        resource = 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(resource)
        return

    if is_quiet():
        print(f"{resource.get('id')}\t{resource.get('resource_name')}\t{resource.get('status')}")
        return

    data: dict[str, Any] = {
        "ID": resource.get("id"),
        "Name": resource.get("resource_name"),
        "Type": resource.get("resource_type"),
        "Namespace": resource.get("namespace"),
        "Status": resource.get("status"),
        "Owner": resource.get("username") or "-",
        "Expires At": resource.get("expires_at") or "-",
        "Lease Hours": resource.get("lease_hours"),
        "K8s Created": resource.get("k8s_created_at") or "-",
        "First Seen": resource.get("first_seen_at") or "-",
        "Cleaned At": resource.get("cleaned_at") or "-",
        "Cleanup Reason": resource.get("cleanup_reason") or "-",
    }
    print_key_value(data, title="Resource Details")


@app.command("renew")
def renew_resource(
    name: str = typer.Argument(..., help="Resource name or ID"),
    hours: int = typer.Option(24, "--hours", "-H", help="Hours to extend lease"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Renew a resource lease (extend expiration time)."""
    pk = _resolve_resource_id(name)

    async def _renew():
        api = get_resource_api()
        return await api.renew_resource(pk, hours=hours)

    try:
        result = asyncio.run(_renew())
    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("id", ""))
    else:
        print_success(
            f"Resource renewed: {result.get('resource_name')} (expires: {result.get('expires_at')})"
        )


@app.command("cleanup")
def cleanup_resource(
    name: str = typer.Argument(..., help="Resource name or ID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Manually clean up a resource (delete from K8s)."""
    pk = _resolve_resource_id(name)

    async def _cleanup():
        api = get_resource_api()
        return await api.cleanup_resource(pk)

    try:
        result = asyncio.run(_cleanup())
    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("cleaned")
    else:
        print_success(f"Resource {result.get('resource_name')} cleaned up.")


@app.command("protect")
def protect_resource(
    name: str = typer.Argument(..., help="Resource name or ID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
) -> None:
    """Mark resource as permanently protected (admin only)."""
    pk = _resolve_resource_id(name)

    async def _protect():
        api = get_resource_api()
        return await api.protect_resource(pk)

    try:
        result = asyncio.run(_protect())
    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("id", ""))
    else:
        print_success(f"Resource {result.get('resource_name')} is now protected.")


def _resolve_resource_id(name: str) -> int:
    """Resolve a resource name or ID to an integer ID.

    If the input is a number, use it directly.
    Otherwise, search by name and return the first match.
    """
    try:
        return int(name)
    except ValueError:
        pass

    # Search by name
    async def _search():
        api = get_resource_api()
        result = await api.list_resources(limit=100)
        items = result.get("items", [])
        for item in items:
            if item.get("resource_name") == name:
                return item.get("id")
        return None

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

    if pk is None:
        print_error(f"Resource not found: {name}")
        raise typer.Exit(1)

    return pk
