"""
NeuralClaw CLI — Beautiful terminal interface.

Commands:
    neuralclaw init     Interactive setup wizard
    neuralclaw chat     Interactive terminal chat session
    neuralclaw gateway  Start the full agent with all configured channels
    neuralclaw status   Show current configuration and status
"""

from __future__ import annotations

import asyncio
import sys
from pathlib import Path

import click
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.text import Text
from rich.markdown import Markdown
from rich.table import Table

from neuralclaw import __version__
from neuralclaw.config import (
    CONFIG_FILE,
    NeuralClawConfig,
    ensure_dirs,
    get_api_key,
    load_config,
    save_default_config,
    set_api_key,
)

import os

if sys.platform == "win32":
    # Force UTF-8 for Windows environments to support the ASCII art banner
    sys.stdout.reconfigure(encoding="utf-8")
    sys.stderr.reconfigure(encoding="utf-8")
    os.environ["PYTHONIOENCODING"] = "utf-8"

console = Console()


# ---------------------------------------------------------------------------
# ASCII Art Banner
# ---------------------------------------------------------------------------

BANNER = """
[bold cyan]
 ███╗   ██╗███████╗██╗   ██╗██████╗  █████╗ ██╗      ██████╗██╗      █████╗ ██╗    ██╗
 ████╗  ██║██╔════╝██║   ██║██╔══██╗██╔══██╗██║     ██╔════╝██║     ██╔══██╗██║    ██║
 ██╔██╗ ██║█████╗  ██║   ██║██████╔╝███████║██║     ██║     ██║     ███████║██║ █╗ ██║
 ██║╚██╗██║██╔══╝  ██║   ██║██╔══██╗██╔══██║██║     ██║     ██║     ██╔══██║██║███╗██║
 ██║ ╚████║███████╗╚██████╔╝██║  ██║██║  ██║███████╗╚██████╗███████╗██║  ██║╚███╔███╔╝
 ╚═╝  ╚═══╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝ ╚═════╝╚══════╝╚═╝  ╚═╝ ╚══╝╚══╝
[/bold cyan]
[dim]The Self-Evolving Cognitive Agent Framework[/dim]
"""


# ---------------------------------------------------------------------------
# CLI Group
# ---------------------------------------------------------------------------

@click.group()
@click.version_option(version=__version__)
def main() -> None:
    """NeuralClaw — The Self-Evolving Cognitive Agent Framework."""
    pass


# ---------------------------------------------------------------------------
# Init command
# ---------------------------------------------------------------------------

@main.command()
def init() -> None:
    """Interactive setup wizard — create config and set API keys."""
    console.print(BANNER)
    console.print(Panel("Welcome to NeuralClaw Setup", style="bold green"))

    ensure_dirs()
    config_path = save_default_config()
    console.print(f"\n✅ Config file: [cyan]{config_path}[/cyan]")

    # API key setup
    console.print("\n[bold]Configure LLM Provider[/bold]")
    console.print("NeuralClaw needs at least one LLM provider to function.\n")

    providers = [
        ("openai", "OpenAI (GPT-4o, GPT-4o-mini)"),
        ("anthropic", "Anthropic (Claude 3.5 Sonnet)"),
        ("openrouter", "OpenRouter (multi-model)"),
        ("proxy", "Proxy (Self-hosted ChatGPT/Claude reverse proxy)"),
        ("local", "Local (Ollama — no API key needed)"),
    ]

    for name, label in providers:
        existing = get_api_key(name)
        if existing:
            masked = existing[:8] + "..." + existing[-4:]
            console.print(f"  {label}: [green]configured[/green] ({masked})")
        else:
            if name in ("local", "proxy"):
                hint = "no key needed" if name == "local" else "configure base_url in ~/.neuralclaw/config.toml"
                console.print(f"  {label}: [dim]{hint}[/dim]")
                continue

            key = Prompt.ask(
                f"  {label} API key (Enter to skip)",
                default="",
                show_default=False,
            )
            if key.strip():
                set_api_key(name, key.strip())
                console.print(f"    [green]✓ Saved to OS keychain[/green]")
            else:
                console.print(f"    [dim]skipped[/dim]")

    console.print(Panel(
        "[green]Setup complete![/green]\n\n"
        "  [cyan]neuralclaw channels setup[/cyan]  Configure messaging channels\n"
        "  [cyan]neuralclaw chat[/cyan]            Start interactive chat\n"
        "  [cyan]neuralclaw gateway[/cyan]         Start with all channels\n"
        "  [cyan]neuralclaw status[/cyan]          View configuration",
        title="What's Next",
        style="bold",
    ))


# ---------------------------------------------------------------------------
# Chat command
# ---------------------------------------------------------------------------

@main.command()
@click.option("--provider", "-p", default=None, help="Provider to use (openai, anthropic, openrouter, local)")
def chat(provider: str | None) -> None:
    """Interactive terminal chat session."""
    console.print(BANNER)
    asyncio.run(_chat_loop(provider))


async def _chat_loop(provider_override: str | None = None) -> None:
    """Main interactive chat loop."""
    from neuralclaw.gateway import NeuralClawGateway

    config = load_config()
    gateway = NeuralClawGateway(config, provider_override=provider_override)
    await gateway.initialize()

    provider_name = gateway._provider.name if gateway._provider else "none"
    console.print(Panel(
        f"Provider: [cyan]{provider_name}[/cyan] | "
        f"Skills: [cyan]{gateway._skills.count}[/cyan] | "
        f"Type [bold red]exit[/bold red] or [bold red]quit[/bold red] to stop",
        title="🧠 NeuralClaw Chat",
        style="bold cyan",
    ))
    console.print()

    while True:
        try:
            user_input = Prompt.ask("[bold green]You[/bold green]")
        except (EOFError, KeyboardInterrupt):
            break

        if not user_input.strip():
            continue

        if user_input.strip().lower() in ("exit", "quit", "/quit", "/exit"):
            break

        console.print()  # Spacing

        try:
            response = await gateway.process_message(
                content=user_input,
                author_id="cli_user",
                author_name="User",
                channel_id="cli",
                channel_type_name="CLI",
            )

            console.print(Panel(
                Markdown(response),
                title="🧠 NeuralClaw",
                style="bold cyan",
                padding=(1, 2),
            ))
            console.print()

        except Exception as e:
            console.print(f"[bold red]Error:[/bold red] {e}\n")

    await gateway.stop()
    console.print("\n[dim]Goodbye! 👋[/dim]\n")


# ---------------------------------------------------------------------------
# Channels command group
# ---------------------------------------------------------------------------

@main.group()
def channels() -> None:
    """Manage messaging channel integrations."""
    pass


@channels.command("setup")
def channels_setup() -> None:
    """Guided setup wizard for all messaging channels."""
    console.print(BANNER)
    console.print(Panel("Channel Configuration", style="bold cyan"))

    channel_defs = [
        ("telegram", "Telegram Bot", "Bot token from @BotFather"),
        ("discord", "Discord Bot", "Bot token from Discord Developer Portal"),
        ("slack_bot", "Slack Bot", "Bot User OAuth Token (xoxb-...)"),
        ("slack_app", "Slack App", "App-Level Token (xapp-...)"),
        ("whatsapp", "WhatsApp", "Session ID (auto-generated on first run, press Enter to use default)"),
        ("signal", "Signal", "Phone number (+1234567890)"),
    ]

    console.print("\nConfigure which channels NeuralClaw should connect to.\n")

    for key, label, hint in channel_defs:
        existing = get_api_key(key)
        if existing:
            masked = existing[:6] + "..." + existing[-4:] if len(existing) > 10 else existing
            console.print(f"  {label}: [green]configured[/green] ({masked})")
            change = Prompt.ask(f"    Update? (y/N)", default="n")
            if change.lower() != "y":
                continue

        value = Prompt.ask(f"  {label} — {hint} (Enter to skip)", default="", show_default=False)
        if value.strip():
            set_api_key(key, value.strip())
            console.print(f"    [green]✓ Saved to OS keychain[/green]")
        else:
            console.print(f"    [dim]skipped[/dim]")

    console.print(Panel(
        "[green]Channel setup complete![/green]\n\n"
        "Run [cyan]neuralclaw gateway[/cyan] to start with all configured channels.",
        style="bold",
    ))


@channels.command("list")
def channels_list() -> None:
    """Show configured channels and their status."""
    table = Table(title="Channel Status", style="cyan")
    table.add_column("Channel", style="bold")
    table.add_column("Status")
    table.add_column("Token")

    channel_keys = [
        ("telegram", "Telegram"),
        ("discord", "Discord"),
        ("slack_bot", "Slack Bot"),
        ("slack_app", "Slack App"),
        ("whatsapp", "WhatsApp"),
        ("signal", "Signal"),
    ]

    for key, label in channel_keys:
        token = get_api_key(key)
        if token:
            masked = token[:6] + "..." + token[-4:] if len(token) > 10 else token
            table.add_row(label, "[green]✓ configured[/green]", masked)
        else:
            table.add_row(label, "[dim]not set[/dim]", "—")

    console.print(table)


@channels.command("test")
@click.argument("channel_name", required=False)
def channels_test(channel_name: str | None) -> None:
    """Test channel connectivity before going live."""
    asyncio.run(_test_channels(channel_name))


async def _test_channels(channel_name: str | None) -> None:
    config = load_config()
    from neuralclaw.gateway import NeuralClawGateway

    gw = NeuralClawGateway(config)
    targets = config.channels
    if channel_name:
        targets = [ch for ch in targets if ch.name == channel_name]
        if not targets:
            console.print(f"[red]Channel '{channel_name}' not found in config.[/red]")
            return

    table = Table(title="Channel Connectivity Test", style="cyan")
    table.add_column("Channel", style="bold")
    table.add_column("Status")
    table.add_column("Details")

    builders = {
        "telegram": gw._build_telegram_channel,
        "discord": gw._build_discord_channel,
        "slack": gw._build_slack_channel,
        "whatsapp": gw._build_whatsapp_channel,
        "signal": gw._build_signal_channel,
    }

    for ch in targets:
        if not ch.enabled or not ch.token:
            table.add_row(ch.name, "[dim]skipped[/dim]", "not enabled or no token")
            continue
        builder = builders.get(ch.name)
        if not builder:
            table.add_row(ch.name, "[dim]skipped[/dim]", "no builder")
            continue
        try:
            adapter = builder(ch)
            if adapter:
                ok, msg = await adapter.test_connection()
                if ok:
                    table.add_row(ch.name, "[green]OK[/green]", msg)
                else:
                    table.add_row(ch.name, "[red]FAIL[/red]", msg)
            else:
                table.add_row(ch.name, "[yellow]WARN[/yellow]", "Builder returned None")
        except Exception as e:
            table.add_row(ch.name, "[red]ERROR[/red]", str(e))

    console.print(table)


@channels.command("add")
@click.argument("channel_name")
def channels_add(channel_name: str) -> None:
    """Add and configure a channel interactively."""
    known = {
        "telegram": "Bot token from @BotFather",
        "discord": "Bot token from Discord Developer Portal",
        "slack_bot": "Bot User OAuth Token (xoxb-...)",
        "whatsapp": "Session ID or auth directory path",
        "signal": "Phone number (+1234567890)",
    }
    hint = known.get(channel_name, "Token or credential")
    value = Prompt.ask(f"  {channel_name} — {hint}", default="", show_default=False)
    if value.strip():
        set_api_key(channel_name, value.strip())
        console.print(f"  [green]✓[/green] Saved '{channel_name}' to keychain")
    else:
        console.print("  [dim]Cancelled — no value provided.[/dim]")


@channels.command("remove")
@click.argument("channel_name")
def channels_remove(channel_name: str) -> None:
    """Remove a channel's stored credentials."""
    from neuralclaw.config import _set_secret
    # Overwrite with empty to effectively remove
    _set_secret(f"{channel_name}_api_key", "")
    console.print(f"  [green]✓[/green] Removed '{channel_name}' credentials")


# ---------------------------------------------------------------------------
# Doctor / Repair commands
# ---------------------------------------------------------------------------

@main.command()
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
def doctor(json_output: bool) -> None:
    """Diagnose all subsystems — config, providers, channels, memory, bus."""
    console.print(BANNER)
    console.print(Panel("NeuralClaw Doctor", style="bold cyan"))

    try:
        config = load_config()
    except Exception:
        config = None

    from neuralclaw.health import HealthChecker, CheckStatus
    checker = HealthChecker(config)
    report = checker.run_all()

    if json_output:
        import json
        data = {
            "healthy": report.healthy,
            "ok": report.ok_count,
            "warnings": report.warn_count,
            "failures": report.fail_count,
            "checks": [
                {"name": c.name, "status": c.status.name, "message": c.message, "repairable": c.repairable}
                for c in report.checks
            ],
        }
        console.print_json(json.dumps(data))
        return

    table = Table(title="Diagnostic Results", style="cyan")
    table.add_column("Check", style="bold")
    table.add_column("Status")
    table.add_column("Details")
    table.add_column("Fix")

    status_style = {
        CheckStatus.OK: "[green]OK[/green]",
        CheckStatus.WARN: "[yellow]WARN[/yellow]",
        CheckStatus.FAIL: "[red]FAIL[/red]",
        CheckStatus.SKIP: "[dim]SKIP[/dim]",
    }

    for check in report.checks:
        table.add_row(
            check.name,
            status_style[check.status],
            check.message,
            check.repair_action if check.repairable else "",
        )

    console.print(table)

    if report.healthy:
        console.print("\n[bold green]All checks passed.[/bold green]\n")
    else:
        console.print(f"\n[bold red]{report.fail_count} issue(s) found.[/bold red]")
        if report.repairable:
            console.print("[dim]Run [cyan]neuralclaw repair[/cyan] to fix automatically.[/dim]\n")


@main.command()
@click.option("--dry-run", is_flag=True, help="Show what would be fixed without changing anything")
@click.option("--backup/--no-backup", default=True, help="Backup config before repair")
def repair(dry_run: bool, backup: bool) -> None:
    """Fix common issues — corrupt DBs, stale auth, broken config."""
    console.print(BANNER)
    console.print(Panel("NeuralClaw Repair", style="bold yellow"))

    try:
        config = load_config()
    except Exception:
        config = None

    if dry_run:
        from neuralclaw.health import HealthChecker
        checker = HealthChecker(config)
        report = checker.run_all()
        console.print("\n[dim]Dry run — no changes will be made.[/dim]")
        for check in report.repairable:
            console.print(f"  Would fix: [bold]{check.name}[/bold] — {check.repair_action}")
        if not report.repairable:
            console.print("  [green]Nothing to repair.[/green]")
        console.print()
        return

    if backup:
        from neuralclaw.config import backup_config
        bp = backup_config()
        if bp:
            console.print(f"  [green]Backed up config to {bp}[/green]")

    from neuralclaw.health import RepairEngine
    engine = RepairEngine(config)
    fixes = engine.run_all()

    if fixes:
        console.print("\n[bold]Repairs performed:[/bold]")
        for fix in fixes:
            console.print(f"  [green]✓[/green] {fix}")
    else:
        console.print("\n[green]Nothing to repair — system is healthy.[/green]")

    console.print("\n[dim]Run [cyan]neuralclaw doctor[/cyan] to verify.[/dim]\n")


# ---------------------------------------------------------------------------
# Gateway command
# ---------------------------------------------------------------------------

@main.command()
@click.option("--federation-port", default=None, type=int, help="Override federation port.")
@click.option("--dashboard-port", default=None, type=int, help="Override dashboard port.")
@click.option("--web-port", default=None, type=int, help="Override web chat port.")
@click.option("--name", default=None, help="Override node name.")
@click.option("--seed", default=None, help="Seed node to join (e.g. http://localhost:8100).")
def gateway(federation_port, dashboard_port, web_port, name, seed) -> None:
    """Start the full agent with all configured channels."""
    console.print(BANNER)
    asyncio.run(_run_gateway(
        federation_port=federation_port,
        dashboard_port=dashboard_port,
        web_port=web_port,
        node_name=name,
        seed_node=seed,
    ))


async def _run_gateway(
    federation_port: int | None = None,
    dashboard_port: int | None = None,
    web_port: int | None = None,
    node_name: str | None = None,
    seed_node: str | None = None,
) -> None:
    """Run the full gateway with channels."""
    from neuralclaw.gateway import NeuralClawGateway

    config = load_config()

    # Apply CLI overrides
    if federation_port is not None:
        config.federation.port = federation_port
    if dashboard_port is not None:
        config.dashboard_port = dashboard_port
    if node_name is not None:
        config.federation.node_name = node_name
    if seed_node is not None:
        if seed_node not in config.federation.seed_nodes:
            config.federation.seed_nodes.append(seed_node)

    gw = NeuralClawGateway(config)
    gw.build_channels(web_port=web_port or 8081)

    try:
        await gw.run_forever()
    except KeyboardInterrupt:
        await gw.stop()


# ---------------------------------------------------------------------------
# Status command
# ---------------------------------------------------------------------------

@main.command()
def status() -> None:
    """Show current configuration and status."""
    console.print(BANNER)

    config = load_config()

    table = Table(title="NeuralClaw Configuration", style="cyan")
    table.add_column("Setting", style="bold")
    table.add_column("Value")

    table.add_row("Config File", str(CONFIG_FILE))
    table.add_row("Name", config.name)
    table.add_row("Log Level", config.log_level)

    # Providers
    providers = ["openai", "anthropic", "openrouter", "proxy", "local"]
    for p in providers:
        key = get_api_key(p)
        status_str = "[green]✓ configured[/green]" if key else "[dim]not set[/dim]"
        if p in ("local", "proxy"):
            status_str = "[dim]no key needed[/dim]"
        table.add_row(f"Provider: {p}", status_str)

    table.add_row("Primary Provider", config.primary_provider.name if config.primary_provider else "none")

    # Channels (unified — all channels now in config.channels)
    for ch in config.channels:
        ch_status = "[green]enabled[/green]" if ch.enabled else "[dim]disabled[/dim]"
        table.add_row(f"Channel: {ch.name}", ch_status)

    # Security
    table.add_row("Threat Threshold", str(config.security.threat_threshold))
    table.add_row("Block Threshold", str(config.security.block_threshold))
    table.add_row("Shell Execution", "allowed" if config.security.allow_shell_execution else "denied")

    console.print(table)
    console.print()


# ---------------------------------------------------------------------------
# Dashboard command
# ---------------------------------------------------------------------------

@main.command()
@click.option("--port", default=8080, help="Dashboard port")
def dashboard(port: int) -> None:
    """Launch the NeuralClaw web dashboard."""
    console.print(BANNER)
    console.print("[bold green]Starting NeuralClaw Dashboard...[/bold green]\n")
    asyncio.run(_run_dashboard(port))


async def _run_dashboard(port: int) -> None:
    from neuralclaw.dashboard import Dashboard
    dash = Dashboard(port=port)
    await dash.start()
    console.print(f"[bold]Dashboard running at[/bold] [cyan]http://localhost:{port}[/cyan]")
    console.print("[dim]Press Ctrl+C to stop[/dim]\n")
    try:
        await asyncio.Event().wait()
    except KeyboardInterrupt:
        pass
    finally:
        await dash.stop()


# ---------------------------------------------------------------------------
# Swarm command group
# ---------------------------------------------------------------------------

@main.group()
def swarm() -> None:
    """Manage swarm agents and delegations."""
    pass


@swarm.command("status")
def swarm_status() -> None:
    """Show active swarm agents and mesh status."""
    console.print(BANNER)

    from neuralclaw.swarm.mesh import AgentMesh
    mesh = AgentMesh()
    status_info = mesh.get_mesh_status()

    table = Table(title="Swarm Mesh Status", style="cyan")
    table.add_column("Property", style="bold")
    table.add_column("Value")

    table.add_row("Total Agents", str(status_info["total_agents"]))
    table.add_row("Online Agents", str(status_info["online_agents"]))
    table.add_row("Total Messages", str(status_info["total_messages"]))

    console.print(table)

    if status_info["agents"]:
        agent_table = Table(title="Registered Agents", style="green")
        agent_table.add_column("Name", style="bold")
        agent_table.add_column("Status")
        agent_table.add_column("Capabilities")
        agent_table.add_column("Active Tasks")
        agent_table.add_column("Endpoint")

        for a in status_info["agents"]:
            agent_table.add_row(
                a["name"],
                a["status"],
                ", ".join(a["capabilities"]),
                str(a["active_tasks"]),
                a["endpoint"],
            )
        console.print(agent_table)
    else:
        console.print("\n[dim]No agents registered on the mesh.[/dim]")
        console.print("[dim]Agents are registered when the gateway runs.[/dim]")
    console.print()


@swarm.command("spawn")
@click.argument("name")
@click.option("--capabilities", "-c", default="general", help="Comma-separated capabilities.")
@click.option("--description", "-d", default="", help="Agent description.")
@click.option("--endpoint", "-e", default=None, help="Remote agent endpoint URL.")
def swarm_spawn(name: str, capabilities: str, description: str, endpoint: str | None) -> None:
    """Spawn a new agent on the swarm mesh.

    For remote agents, provide --endpoint to register a proxy.

    \b
    Examples:
        neuralclaw swarm spawn researcher -c "search,analysis"
        neuralclaw swarm spawn remote-agent -e http://peer:8100
    """
    caps = [c.strip() for c in capabilities.split(",") if c.strip()]
    desc = description or f"Agent '{name}' with capabilities: {', '.join(caps)}"

    console.print(Panel(f"[bold]Spawn Agent: {name}[/bold]", border_style="green"))
    console.print(f"  Name: [bold]{name}[/bold]")
    console.print(f"  Description: {desc}")
    console.print(f"  Capabilities: {caps}")

    if endpoint:
        console.print(f"  Endpoint: [cyan]{endpoint}[/cyan]")
        console.print(f"  Type: [cyan]remote[/cyan]")
    else:
        console.print(f"  Type: [cyan]local[/cyan]")

    console.print("\n[dim]Agents are spawned at runtime via the gateway.[/dim]")
    console.print("[dim]Use the Python API: gateway.spawner.spawn_local(...)[/dim]")
    console.print()


# ---------------------------------------------------------------------------
# Migrate from OpenClaw
# ---------------------------------------------------------------------------


@main.command()
@click.option("--source", default=None, help="Path to OpenClaw directory (auto-detected if omitted)")
@click.option("--dry-run", is_flag=True, help="Scan only — don't migrate anything")
def migrate(source: str | None, dry_run: bool) -> None:
    """Migrate from OpenClaw / Clawdbot / Moltbot to NeuralClaw."""
    from neuralclaw.migrate import OpenClawMigrator

    console.print(Panel(
        "[bold]OpenClaw → NeuralClaw Migration Tool[/bold]\n"
        "[dim]Imports your config, channel tokens, and memories[/dim]",
        border_style="blue",
    ))

    migrator = OpenClawMigrator(source)

    if not migrator.found:
        console.print("\n[yellow]No OpenClaw installation found.[/yellow]")
        console.print("[dim]Searched: ~/.openclaw, ~/clawd, ~/.clawdbot, ~/.moltbot[/dim]")
        if not source:
            console.print("\n[dim]Tip: Use --source /path/to/openclaw to specify manually[/dim]")
        return

    console.print(f"\n[green]✓[/green] Found OpenClaw at: [bold]{migrator.source_path}[/bold]\n")

    # Scan
    scan = migrator.scan()
    scan_table = Table(show_header=False, box=None, padding=(0, 2))
    scan_table.add_row("Config:", "[green]found[/green]" if scan["config_exists"] else "[red]not found[/red]")
    scan_table.add_row("Memory files:", str(scan["memory_files"]))
    scan_table.add_row("Channels:", ", ".join(scan.get("channels", [])) or "none")
    scan_table.add_row("Providers:", ", ".join(scan.get("providers", [])) or "none")
    console.print(scan_table)

    if dry_run:
        console.print("\n[dim]Dry run complete — no changes made.[/dim]")
        return

    console.print("\n[bold]Migrating...[/bold]\n")
    report = migrator.run_full_migration()

    # Report
    result_table = Table(show_header=False, box=None, padding=(0, 2))
    result_table.add_row("Config migrated:", "[green]✓[/green]" if report.config_migrated else "[red]✗[/red]")
    result_table.add_row("Memories imported:", str(report.memories_imported))
    result_table.add_row("Channels:", ", ".join(report.channels_migrated) or "none")
    result_table.add_row("API keys detected:", ", ".join(report.api_keys_migrated) or "none")
    console.print(result_table)

    if report.warnings:
        console.print("\n[yellow]Warnings:[/yellow]")
        for w in report.warnings:
            console.print(f"  [yellow]⚠[/yellow] {w}")

    if report.errors:
        console.print("\n[red]Errors:[/red]")
        for e in report.errors:
            console.print(f"  [red]✗[/red] {e}")

    if report.api_keys_migrated:
        console.print("\n[dim]Note: API keys were detected but not copied (security).")
        console.print("Run `neuralclaw init` to securely store them in your keychain.[/dim]")

    console.print("\n[green]Migration complete![/green]\n")


# ---------------------------------------------------------------------------
# Benchmark
# ---------------------------------------------------------------------------


@main.command()
@click.option("--category", default=None, help="Run a specific category (perception, memory, security, reasoning, latency)")
@click.option("--export", is_flag=True, help="Export results to JSON")
def benchmark(category: str | None, export: bool) -> None:
    """Run the NeuralClaw benchmark suite."""
    import asyncio
    from neuralclaw.benchmark import BenchmarkSuite

    console.print(Panel(
        "[bold]NeuralClaw Benchmark Suite[/bold]\n"
        "[dim]Measuring perception, memory, security, reasoning, and latency[/dim]",
        border_style="cyan",
    ))

    suite = BenchmarkSuite()

    with console.status("[bold cyan]Running benchmarks...[/bold cyan]"):
        if category:
            result = asyncio.run(suite.run_category(category))
            report = suite._report
            report.results = [result]
        else:
            report = asyncio.run(suite.run_all())

    # Display results
    results_table = Table(title="Benchmark Results", show_lines=True)
    results_table.add_column("Benchmark", style="bold")
    results_table.add_column("Score", justify="center")
    results_table.add_column("Pass/Total", justify="center")
    results_table.add_column("Avg Latency", justify="right")
    results_table.add_column("Time", justify="right")

    for r in report.results:
        score_color = "green" if r.score >= 0.8 else "yellow" if r.score >= 0.5 else "red"
        results_table.add_row(
            r.name,
            f"[{score_color}]{r.score:.0%}[/{score_color}]",
            f"{r.passed}/{r.total}",
            f"{r.latency_ms:.1f}ms",
            f"{r.elapsed_seconds:.1f}s",
        )

    console.print(results_table)

    overall_color = "green" if report.overall_score >= 0.8 else "yellow" if report.overall_score >= 0.5 else "red"
    console.print(f"\n[bold]Overall Score:[/bold] [{overall_color}]{report.overall_score:.0%}[/{overall_color}]")
    console.print(f"[dim]Total time: {report.total_elapsed_seconds:.1f}s[/dim]\n")

    if export:
        path = suite.export_json()
        console.print(f"[green]✓[/green] Results exported to: [bold]{path}[/bold]\n")


# ---------------------------------------------------------------------------
# Federation
# ---------------------------------------------------------------------------


@main.command()
@click.option("--port", default=8100, help="Federation port to query.")
def federation(port: int) -> None:
    """Show federation status and connected nodes."""
    console.print(Panel(
        "[bold]NeuralClaw Federation[/bold]\n"
        "[dim]Cross-network agent discovery and communication[/dim]",
        border_style="blue",
    ))

    # Try to query a running federation server
    import json
    import urllib.request
    try:
        url = f"http://127.0.0.1:{port}/federation/status"
        with urllib.request.urlopen(url, timeout=3) as resp:
            data = json.loads(resp.read())

        status_table = Table(title="Federation Status", style="cyan")
        status_table.add_column("Property", style="bold")
        status_table.add_column("Value")
        status_table.add_row("Total Nodes", str(data.get("total_nodes", 0)))
        status_table.add_row("Online Nodes", str(data.get("online_nodes", 0)))
        status_table.add_row("Blacklisted", str(data.get("blacklisted", 0)))
        console.print(status_table)

        nodes = data.get("nodes", [])
        if nodes:
            node_table = Table(title="Connected Nodes", style="green")
            node_table.add_column("Name", style="bold")
            node_table.add_column("Status")
            node_table.add_column("Trust")
            node_table.add_column("Capabilities")
            node_table.add_column("Endpoint")

            for n in nodes:
                trust = n.get("trust", 0.0)
                trust_color = "green" if trust >= 0.7 else "yellow" if trust >= 0.4 else "red"
                node_table.add_row(
                    n.get("name", "?"),
                    n.get("status", "?"),
                    f"[{trust_color}]{trust:.2f}[/{trust_color}]",
                    ", ".join(n.get("capabilities", [])) or "none",
                    n.get("endpoint", "?"),
                )
            console.print(node_table)
        else:
            console.print("\n[dim]No nodes connected.[/dim]")

    except Exception:
        console.print(f"\n[dim]Federation server not running on port {port}.[/dim]")
        console.print("[dim]Start the gateway first: neuralclaw gateway[/dim]")
        # Fall back to protocol info
        info_table = Table(show_header=False, box=None, padding=(0, 2))
        info_table.add_row("Protocol:", "HTTP/JSON")
        info_table.add_row("Discovery:", "/federation/discover")
        info_table.add_row("Messaging:", "/federation/message")
        info_table.add_row("Heartbeat:", "/federation/heartbeat")
        info_table.add_row("Status:", "/federation/status")
        console.print(info_table)
    console.print()


# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    main()
