"""
Connections command module
"""

import time
from typing import Annotated

from cyclopts import App, Parameter
from rich.table import Table

from exosphere import app_config
from exosphere.commands.utils import (
    HostArg,
    console,
    err_console,
    get_hosts_or_all,
    require_interactive,
)

ROOT_HELP = """
Connection State Management Commands

Commands to inspect the state of SSH connections to inventory hosts.
These commands are only useful when SSH Pipelining is enabled,
otherwise no persistent connections to hosts are maintained.

Only useful from Interactive Mode, as connections are not maintained
between separate CLI invocations.
"""

# Interactive-only group: hidden from normal CLI help
# It can still be invoked directly, but won't show up in the main help
# Interactive Mode (the REPL) will unhide it at runtime.
app = App(name="connections", help=ROOT_HELP, help_flags=["--help"], show=False)


def _format_duration(seconds: int) -> str:
    """Format duration in seconds to human-readable string."""
    if seconds < 60:
        return f"{seconds}s"
    elif seconds < 3600:
        minutes = seconds // 60
        remaining_seconds = seconds % 60
        return (
            f"{minutes}m {remaining_seconds}s" if remaining_seconds else f"{minutes}m"
        )
    else:
        hours = seconds // 3600
        remaining_minutes = (seconds % 3600) // 60
        return f"{hours}h {remaining_minutes}m" if remaining_minutes else f"{hours}h"


@app.command(synonym=["list", "status"])
@require_interactive
def show(
    *names: HostArg,
    active_only: Annotated[
        bool, Parameter(name=["--active", "-a"], negative="")
    ] = False,
) -> int:
    """
    Show SSH connection state for inventory hosts

    Display the current SSH connection state for specified hosts, or
    all hosts if none are specified.

    Connections that have been idle for longer than the configured
    maximum age will be marked as "Expiring".

    Only useful when SSH Pipelining is enabled, and exclusively from
    interactive mode, as connections are not maintained between
    individual CLI invocations.

    Parameters
    ----------
    names
        Hosts to show connection state for. If omitted, shows all hosts.
    active_only
        Show only hosts with active connections.
    """
    if not app_config["options"]["ssh_pipelining"]:
        err_console.print("[yellow]SSH Pipelining is currently disabled.[/yellow]")
        err_console.print("No persistent connections to hosts are maintained.")
        return 2  # Application error: feature disabled

    pipelining_max_age = app_config["options"]["ssh_pipelining_lifetime"]
    pipelining_interval = app_config["options"]["ssh_pipelining_reap_interval"]

    hosts = get_hosts_or_all(names)

    if hosts is None:
        return 1  # Input error, no host to operate on

    # Filter for active connections if requested
    if active_only:
        hosts = [h for h in hosts if h.is_connected]
        if not hosts:
            console.print("No active connections.")
            return 0

    table_title = "SSH Connections"

    if active_only:
        table_title += " (Active Only)"

    table = Table(
        "Host",
        "IP",
        "Port",
        "Idle",
        "State",
        title=table_title,
        caption=f"Idle connections older than {pipelining_max_age}s are closed every {pipelining_interval}s",
        caption_justify="right",
    )

    for host in hosts:
        host_name = host.name
        host_ip = host.ip
        host_port = host.port

        if host.is_connected and host.connection_last_used is not None:
            idle_seconds = round(time.time() - host.connection_last_used)
            host_idle = _format_duration(idle_seconds)

            # Expiring connections should be marked as such
            # The reaper adds some splay time.
            if idle_seconds >= pipelining_max_age:
                state = "[yellow]Expiring[/yellow]"
            else:
                state = "[green]Connected[/green]"
        else:
            host_idle = "[dim]—[/dim]"
            idle_seconds = None
            state = "[dim]Inactive[/dim]"

        table.add_row(
            str(host_name),
            str(host_ip),
            str(host_port),
            host_idle,
            state,
        )

    console.print(table)

    return 0


@app.command
@require_interactive
def close(
    *names: HostArg,
    verbose: Annotated[bool, Parameter(name=["--verbose", "-v"], negative="")] = False,
) -> int:
    """
    Close SSH connections explicitly

    Close SSH connections to specified hosts, or all hosts if none are specified.

    Only useful when SSH Pipelining is enabled, and exclusively from
    interactive mode, as connections are not maintained between
    individual CLI invocations.

    Parameters
    ----------
    names
        Hosts to close connections for. If omitted, close all connections.
    verbose
        Show detailed output of closed connections.
    """
    if not app_config["options"]["ssh_pipelining"]:
        err_console.print("[yellow]SSH Pipelining is currently disabled.[/yellow]")
        err_console.print("No persistent connections to hosts are maintained.")
        return 2  # Application error

    hosts = get_hosts_or_all(names)

    if hosts is None:
        return 1  # Input error, no host to operate on

    closed_count = 0
    inactive_count = 0

    for host in hosts:
        if not host.is_connected:
            inactive_count += 1
            continue

        host.close()
        closed_count += 1

        if verbose:
            console.print(f"  [bold]{host.name}[/bold]: Connection closed.")

    if closed_count > 0:
        console.print(f"Closed [bold]{closed_count}[/bold] active connection(s).")

    if verbose and inactive_count > 0:
        console.print(
            f"[dim]Skipped {inactive_count} host(s) with no active connections.[/dim]"
        )

    return 0
