"""CLI interface for Curadise Agent."""

from __future__ import annotations

import asyncio
from typing import TYPE_CHECKING, Annotated

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

from curadise_agent import __version__
from curadise_agent.config.loader import load_config, validate_config_file
from curadise_agent.config.settings import Settings
from curadise_agent.errors import ConfigurationError, CuradiseAgentError
from curadise_agent.utils.logging import setup_logging

if TYPE_CHECKING:
    from pathlib import Path

app = typer.Typer(
    name="curadise-agent",
    help="Curadise monitoring agent - collect metrics, send heartbeats, execute commands.",
    no_args_is_help=True,
)

config_app = typer.Typer(help="Configuration management commands.")
app.add_typer(config_app, name="config")

console = Console()
error_console = Console(stderr=True)


def version_callback(value: bool) -> None:
    """Print version and exit."""
    if value:
        console.print(f"curadise-agent {__version__}")
        raise typer.Exit()


@app.callback()
def main(
    version: Annotated[
        bool | None,
        typer.Option("--version", "-v", callback=version_callback, is_eager=True),
    ] = None,
) -> None:
    """Curadise Agent CLI."""
    pass


@app.command()
def start(
    config_file: Annotated[
        Path | None,
        typer.Option("--config", "-c", help="Path to configuration file"),
    ] = None,
    foreground: Annotated[
        bool,
        typer.Option("--foreground", "-f", help="Run in foreground (don't daemonize)"),
    ] = True,
    log_level: Annotated[
        str | None,
        typer.Option("--log-level", "-l", help="Log level (DEBUG, INFO, WARNING, ERROR)"),
    ] = None,
) -> None:
    """Start the Curadise agent."""
    try:
        # Load configuration
        settings = Settings()
        if log_level:
            settings = Settings(log_level=log_level)

        config = load_config(config_path=config_file, settings=settings)

        # Setup logging
        log = setup_logging(config.logging)
        log.info("starting_agent", config_file=str(config_file) if config_file else "default")

        # Import and run main loop
        from curadise_agent.main import run_agent

        asyncio.run(run_agent(config))

    except ConfigurationError as e:
        error_console.print(f"[red]Configuration error:[/red] {e.message}")
        raise typer.Exit(1)
    except KeyboardInterrupt:
        console.print("\n[yellow]Interrupted by user[/yellow]")
        raise typer.Exit(130)
    except CuradiseAgentError as e:
        error_console.print(f"[red]Error:[/red] {e.message}")
        raise typer.Exit(1)


@app.command()
def register(
    config_file: Annotated[
        Path | None,
        typer.Option("--config", "-c", help="Path to configuration file"),
    ] = None,
    enrollment_token: Annotated[
        str | None,
        typer.Option("--token", "-t", help="Enrollment token"),
    ] = None,
    force: Annotated[
        bool,
        typer.Option("--force", help="Force re-registration"),
    ] = False,
) -> None:
    """Register the agent with the Curadise server."""
    try:
        from curadise_agent.auth.registration import RegistrationService
        from curadise_agent.state.manager import create_state_manager
        from curadise_agent.transport.client import create_transport_client
        from curadise_agent.utils.system_info import collect_system_info

        # Load configuration
        settings = Settings()
        if enrollment_token:
            from pydantic import SecretStr

            settings = Settings(enrollment_token=SecretStr(enrollment_token))

        config = load_config(config_path=config_file, settings=settings)
        setup_logging(config.logging)

        # Check existing registration
        state_manager = create_state_manager(config.state)
        asyncio.run(state_manager.load())

        if state_manager.is_registered and not force:
            console.print(f"[yellow]Agent already registered:[/yellow] {state_manager.agent_id}")
            console.print("Use --force to re-register")
            raise typer.Exit(0)

        # Get enrollment token
        token = enrollment_token
        if not token and config.auth.enrollment_token:
            token = config.auth.enrollment_token.get_secret_value()

        if not token:
            error_console.print("[red]No enrollment token provided[/red]")
            error_console.print("Use --token or set CURADISE_ENROLLMENT_TOKEN")
            raise typer.Exit(1)

        # Create transport client and register
        transport = create_transport_client(config.server, config.auth, config.retry)

        async def do_register() -> None:
            await transport.start()
            try:
                registration = RegistrationService(transport, state_manager)
                system_info = collect_system_info()
                await registration.register(token, system_info.to_dict(), config.tags)
                console.print(f"[green]Successfully registered:[/green] {state_manager.agent_id}")
            finally:
                await transport.stop()

        asyncio.run(do_register())

    except CuradiseAgentError as e:
        error_console.print(f"[red]Registration failed:[/red] {e.message}")
        raise typer.Exit(1)


@app.command()
def status(
    config_file: Annotated[
        Path | None,
        typer.Option("--config", "-c", help="Path to configuration file"),
    ] = None,
    json_output: Annotated[
        bool,
        typer.Option("--json", "-j", help="Output as JSON"),
    ] = False,
) -> None:
    """Show agent status."""
    try:
        import orjson

        from curadise_agent.state.manager import create_state_manager

        config = load_config(config_path=config_file)
        state_manager = create_state_manager(config.state)
        asyncio.run(state_manager.load())

        status_data = state_manager.get_status()

        if json_output:
            console.print(orjson.dumps(status_data, option=orjson.OPT_INDENT_2).decode())
        else:
            table = Table(title="Agent Status")
            table.add_column("Property", style="cyan")
            table.add_column("Value", style="green")

            table.add_row("State", status_data["state"])
            table.add_row("Registered", "Yes" if status_data["is_registered"] else "No")
            table.add_row("Agent ID", status_data["agent_id"] or "N/A")
            table.add_row("Authenticated", "Yes" if status_data["is_authenticated"] else "No")

            console.print(table)

    except Exception as e:
        if json_output:
            import orjson

            console.print(orjson.dumps({"error": str(e)}).decode())
        else:
            error_console.print(f"[red]Error:[/red] {e}")
        raise typer.Exit(1)


@config_app.command("validate")
def config_validate(
    config_file: Annotated[
        Path,
        typer.Argument(help="Path to configuration file to validate"),
    ],
) -> None:
    """Validate a configuration file."""
    if not config_file.exists():
        error_console.print(f"[red]File not found:[/red] {config_file}")
        raise typer.Exit(1)

    is_valid, errors = validate_config_file(config_file)

    if is_valid:
        console.print(f"[green]Configuration is valid:[/green] {config_file}")
    else:
        error_console.print(f"[red]Configuration is invalid:[/red] {config_file}")
        for error in errors:
            error_console.print(f"  - {error}")
        raise typer.Exit(1)


@config_app.command("show")
def config_show(
    config_file: Annotated[
        Path | None,
        typer.Option("--config", "-c", help="Path to configuration file"),
    ] = None,
    section: Annotated[
        str | None,
        typer.Option("--section", "-s", help="Show specific section"),
    ] = None,
) -> None:
    """Show effective configuration."""
    try:
        import orjson

        config = load_config(config_path=config_file)
        config_dict = config.model_dump(mode="json")

        if section:
            if section in config_dict:
                config_dict = {section: config_dict[section]}
            else:
                error_console.print(f"[red]Unknown section:[/red] {section}")
                error_console.print(f"Available sections: {', '.join(config_dict.keys())}")
                raise typer.Exit(1)

        console.print(orjson.dumps(config_dict, option=orjson.OPT_INDENT_2).decode())

    except ConfigurationError as e:
        error_console.print(f"[red]Configuration error:[/red] {e.message}")
        raise typer.Exit(1)


@app.command()
def unregister(
    config_file: Annotated[
        Path | None,
        typer.Option("--config", "-c", help="Path to configuration file"),
    ] = None,
    confirm: Annotated[
        bool,
        typer.Option("--yes", "-y", help="Skip confirmation"),
    ] = False,
) -> None:
    """Unregister the agent and clear credentials."""
    try:
        from curadise_agent.state.manager import create_state_manager

        config = load_config(config_path=config_file)
        state_manager = create_state_manager(config.state)
        asyncio.run(state_manager.load())

        if not state_manager.is_registered:
            console.print("[yellow]Agent is not registered[/yellow]")
            raise typer.Exit(0)

        if not confirm:
            confirm = typer.confirm(
                f"Unregister agent {state_manager.agent_id}? This will clear all credentials."
            )
            if not confirm:
                raise typer.Exit(0)

        state_manager.clear_credentials()
        console.print("[green]Agent unregistered successfully[/green]")

    except CuradiseAgentError as e:
        error_console.print(f"[red]Error:[/red] {e.message}")
        raise typer.Exit(1)


if __name__ == "__main__":
    app()
