"""Connection management commands: connect, connections, disconnect."""

import asyncio
import os

import click

from mcpbundles.config import AuthError, CLISettings
from mcpbundles.connections import ConnectionManager
from mcpbundles.mcp_client import hub_session, ConnectionError
from mcpbundles.output import render_success, render_error, render_warning, print_json, stdout_console

from rich.panel import Panel
from rich.table import Table


def _resolve_auth_for_connect(settings: CLISettings, oauth: bool, oauth_base_url: str) -> tuple[str, dict | None]:
    """Resolve auth token for a new connection.

    Returns (auth_token, refresh_data_or_none).

    Precedence:
      1. --oauth flag → browser OAuth flow
      2. MCPBUNDLES_API_KEY env var → API key
      3. Interactive prompt → API key
    """
    if oauth:
        from mcpbundles.auth import oauth_flow
        token_data = oauth_flow(oauth_base_url)
        refresh_data = {
            "client_id": token_data["client_id"],
            "client_secret": token_data["client_secret"],
            "refresh_token": token_data["refresh_token"],
            "expires_at": token_data["expires_at"],
        }
        return token_data["access_token"], refresh_data

    env_key = os.getenv("MCPBUNDLES_API_KEY")
    if env_key:
        return env_key, None

    token = click.prompt("API key", hide_input=True, prompt_suffix=": ")
    if not token or not token.strip():
        raise AuthError("No API key provided.")
    return token.strip(), None


@click.command()
@click.argument("name")
@click.option("--url", help="Override server URL (default: mcp.mcpbundles.com)")
@click.option("--endpoint", default="/hub/", help="MCP endpoint path (default: /hub/)")
@click.option("--bundle", help="Connect to a bundle endpoint by slug (sets endpoint to /mcp/bundle/<slug>/)")
@click.option("--workspace", help="Workspace ID")
@click.option("--oauth", is_flag=True, help="Authenticate via browser OAuth flow instead of API key")
@click.option("--default", "is_default", is_flag=True, help="Set as default connection")
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
@click.pass_context
def connect(ctx: click.Context, name: str, url: str | None, endpoint: str, bundle: str | None, workspace: str | None, oauth: bool, is_default: bool, as_json: bool) -> None:
    """Create a named connection to an MCP endpoint.

    Auth is resolved automatically: env var → interactive prompt → --oauth.
    The credential is encrypted and stored with the connection.

    Examples:
        mcpbundles connect hub --default
        mcpbundles connect hubspot --bundle hubspot
        MCPBUNDLES_API_KEY=mb_xxx mcpbundles connect prod
        mcpbundles connect staging --oauth
    """
    if bundle:
        endpoint = f"/mcp/bundle/{bundle}/"

    settings: CLISettings = ctx.obj["settings"]
    base_url = url or settings.base_url

    try:
        auth_token, refresh_data = _resolve_auth_for_connect(
            settings, oauth, settings.oauth_base_url,
        )
    except AuthError as exc:
        render_error(str(exc))
        raise SystemExit(1)

    asyncio.run(_connect_impl(
        name, base_url, endpoint, workspace, is_default, as_json,
        auth_token, refresh_data,
    ))


async def _connect_impl(
    name: str, base_url: str, endpoint: str, workspace: str | None,
    is_default: bool, as_json: bool,
    auth_token: str, refresh_data: dict | None,
) -> None:
    stdout_console.print(f"Connecting to [cyan]{base_url}{endpoint}[/] ...")

    try:
        async with hub_session(auth_token, base_url, endpoint) as session:
            result = await session.list_tools()
            tool_count = len(result.tools)
    except (AuthError, ConnectionError) as exc:
        render_error(f"Connection failed: {exc}")
        raise SystemExit(1)

    mgr = ConnectionManager()
    existing = mgr.get(name)
    if existing:
        render_warning(f"Connection '{name}' already exists — overwriting.")
        mgr.remove(name)

    conn = mgr.create(
        name=name,
        url=base_url,
        endpoint=endpoint,
        workspace_id=workspace,
        is_default=is_default,
        auth_token=auth_token,
        refresh_data=refresh_data,
    )

    auth_label = "oauth" if refresh_data else "api-key"
    if as_json:
        from dataclasses import asdict
        safe = {k: v for k, v in asdict(conn).items()
                if k not in ("auth_token_encrypted", "auth_refresh_encrypted")}
        safe["auth_type"] = auth_label
        print_json(safe)
    else:
        render_success(f"Connection '{name}' created → {conn.display_target} ({tool_count} tools, {auth_label})")
        if is_default:
            stdout_console.print(f"  Set as [bold]default[/bold] connection")


@click.command("connections")
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
def list_connections(as_json: bool) -> None:
    """List all named connections."""
    mgr = ConnectionManager()
    conns = mgr.list_connections()

    if not conns:
        render_warning("No connections. Use 'mcpbundles connect <name>' to create one.")
        return

    if as_json:
        safe_list = []
        for c in conns:
            from dataclasses import asdict
            safe = {k: v for k, v in asdict(c).items()
                    if k not in ("auth_token_encrypted", "auth_refresh_encrypted")}
            safe["auth_type"] = c.auth_type
            safe_list.append(safe)
        print_json(safe_list)
        return

    table = Table(show_header=True, header_style="bold", box=None, pad_edge=False)
    table.add_column("Name", style="cyan", no_wrap=True)
    table.add_column("Target", style="white")
    table.add_column("Auth", style="dim")
    table.add_column("Session", style="dim")
    table.add_column("Default", style="green")

    for c in conns:
        session_str = "✓" if c.session_id else "—"
        default_str = "★" if c.is_default else ""
        table.add_row(c.name, c.display_target, c.auth_type, session_str, default_str)

    panel = Panel(table, title=f"Connections ({len(conns)})", border_style="blue", padding=(1, 2))
    stdout_console.print(panel)


@click.command()
@click.argument("name")
def disconnect(name: str) -> None:
    """Remove a named connection."""
    mgr = ConnectionManager()
    if mgr.remove(name):
        render_success(f"Connection '{name}' removed.")
    else:
        render_error(f"Connection '{name}' not found.")
        raise SystemExit(1)
