"""
Nexus CLI — command-line interface for managing multi-agent projects.

Commands:
  nexus init     — Scaffold a new Nexus project
  nexus run      — Run a Nexus agent team from a YAML config
  nexus inspect  — Inspect registered agents and capabilities
  nexus version  — Print version
"""

from __future__ import annotations

import asyncio
import json
import sys
from pathlib import Path
from typing import Any

import click
import yaml
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.tree import Tree

console = Console()


@click.group()
@click.version_option(package_name="nexus-agents")
def main() -> None:
    """Nexus — Protocol-native adaptive multi-agent framework."""
    pass


# ──────────────────────────────────────────────
# nexus init
# ──────────────────────────────────────────────

@main.command()
@click.argument("project_name", default="my-nexus-project")
@click.option("--model", default="gpt-4o", help="Default model to use")
def init(project_name: str, model: str) -> None:
    """Scaffold a new Nexus project."""
    project_dir = Path(project_name)

    if project_dir.exists():
        console.print(f"[red]Error:[/red] Directory '{project_name}' already exists.")
        sys.exit(1)

    project_dir.mkdir(parents=True)

    # Create project structure
    (project_dir / "agents").mkdir()
    (project_dir / "tools").mkdir()

    # nexus.yaml — project config
    config = {
        "name": project_name,
        "version": "0.1.0",
        "model": model,
        "mode": "router",
        "agents": [
            {
                "name": "assistant",
                "instructions": "You are a helpful assistant.",
                "model": model,
            },
        ],
        "budget": {
            "max_tokens": 100000,
            "warning_threshold": 0.7,
        },
    }
    (project_dir / "nexus.yaml").write_text(yaml.dump(config, default_flow_style=False, sort_keys=False))

    # main.py — entry point
    main_py = f'''\
"""
Nexus multi-agent project: {project_name}
Auto-generated by `nexus init`.
"""

import asyncio
from nexus.api import Team


async def main():
    async with Team(model="{model}") as team:
        assistant = team.add_agent(
            name="assistant",
            instructions="You are a helpful assistant.",
        )

        result = await team.run("Hello! What can you do?")
        print(result)


if __name__ == "__main__":
    asyncio.run(main())
'''

    (project_dir / "main.py").write_text(main_py)

    # .env.example
    env_example = """\
# Nexus environment variables
OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# OLLAMA_BASE_URL=http://localhost:11434
"""
    (project_dir / ".env.example").write_text(env_example)

    console.print(Panel(
        f"[green]✓[/green] Project [bold]{project_name}[/bold] created!\n\n"
        f"  cd {project_name}\n"
        f"  pip install nexus-agents\n"
        f"  cp .env.example .env  # add your API key\n"
        f"  python main.py",
        title="🚀 Nexus Project",
        border_style="green",
    ))


# ──────────────────────────────────────────────
# nexus run
# ──────────────────────────────────────────────

@main.command()
@click.option("--config", "-c", default="nexus.yaml", help="Path to nexus.yaml config")
@click.option("--prompt", "-p", default=None, help="Prompt to run (or read from stdin)")
@click.option("--verbose", "-v", is_flag=True, help="Verbose output")
def run(config: str, prompt: str | None, verbose: bool) -> None:
    """Run a Nexus agent team from a YAML config."""
    config_path = Path(config)

    if not config_path.exists():
        console.print(f"[red]Error:[/red] Config file '{config}' not found.")
        console.print("Run [bold]nexus init[/bold] to create a project first.")
        sys.exit(1)

    with open(config_path) as f:
        cfg = yaml.safe_load(f)

    # Get prompt
    if prompt is None:
        if not sys.stdin.isatty():
            prompt = sys.stdin.read().strip()
        else:
            prompt = click.prompt("Enter your prompt")

    if not prompt:
        console.print("[red]Error:[/red] No prompt provided.")
        sys.exit(1)

    asyncio.run(_run_from_config(cfg, prompt, verbose))


async def _run_from_config(cfg: dict[str, Any], prompt: str, verbose: bool) -> None:
    """Execute a team from a YAML config."""
    from nexus.api import Team
    from nexus.orchestration.topology import TopologyMode
    from nexus.types import AgentCapability

    model = cfg.get("model", "gpt-4o")
    mode_str = cfg.get("mode", "router").upper()
    mode = TopologyMode[mode_str] if mode_str in TopologyMode.__members__ else TopologyMode.ROUTER

    async with Team(model=model, mode=mode, verbose=verbose) as team:
        # Register agents from config
        for agent_cfg in cfg.get("agents", []):
            agent_model = agent_cfg.get("model")
            team.add_agent(
                name=agent_cfg["name"],
                instructions=agent_cfg.get("instructions", ""),
                model=agent_model if agent_model != model else None,
                capabilities=AgentCapability(**agent_cfg.get("capabilities", {})),
            )

        # Run
        with console.status("[bold green]Thinking..."):
            result = await team.run(prompt)

        console.print(Panel(
            result,
            title="🤖 Response",
            border_style="blue",
        ))

        # Show metrics if verbose
        if verbose and team.metrics:
            summary = team.metrics.summary()
            console.print(Panel(
                json.dumps(summary, indent=2, default=str),
                title="📊 Metrics",
                border_style="dim",
            ))


# ──────────────────────────────────────────────
# nexus inspect
# ──────────────────────────────────────────────

@main.command()
@click.option("--config", "-c", default="nexus.yaml", help="Path to nexus.yaml config")
def inspect(config: str) -> None:
    """Inspect agents defined in a Nexus config."""
    config_path = Path(config)

    if not config_path.exists():
        console.print(f"[red]Error:[/red] Config file '{config}' not found.")
        sys.exit(1)

    with open(config_path) as f:
        cfg = yaml.safe_load(f)

    # Show project info
    console.print(Panel(
        f"[bold]{cfg.get('name', 'Unknown')}[/bold] v{cfg.get('version', '?')}\n"
        f"Model: {cfg.get('model', 'gpt-4o')}\n"
        f"Mode:  {cfg.get('mode', 'router')}",
        title="🔍 Project Info",
        border_style="cyan",
    ))

    # Show agents table
    agents = cfg.get("agents", [])
    if not agents:
        console.print("[yellow]No agents defined.[/yellow]")
        return

    table = Table(title="Agents", show_header=True, header_style="bold magenta")
    table.add_column("Name", style="bold")
    table.add_column("Model")
    table.add_column("Instructions", max_width=50)
    table.add_column("Tools", justify="right")

    for agent in agents:
        tools = agent.get("tools", [])
        table.add_row(
            agent.get("name", "?"),
            agent.get("model", cfg.get("model", "gpt-4o")),
            (agent.get("instructions", "")[:47] + "..." if len(agent.get("instructions", "")) > 50
             else agent.get("instructions", "")),
            str(len(tools)),
        )

    console.print(table)

    # Show topology
    handoffs = cfg.get("handoffs", [])
    if handoffs:
        tree = Tree("🔗 Handoffs")
        for h in handoffs:
            tree.add(f"{h.get('from', '?')} → {h.get('to', '?')} ({h.get('mode', 'delegate')})")
        console.print(tree)


# ──────────────────────────────────────────────
# nexus chat (interactive)
# ──────────────────────────────────────────────

@main.command()
@click.option("--model", "-m", default="gpt-4o", help="Model to use")
@click.option("--config", "-c", default=None, help="Optional nexus.yaml config")
def chat(model: str, config: str | None) -> None:
    """Start an interactive chat session."""
    asyncio.run(_interactive_chat(model, config))


async def _interactive_chat(model: str, config_path: str | None) -> None:
    """Run an interactive chat loop."""
    from nexus.api import Team

    cfg: dict[str, Any] = {}
    if config_path:
        with open(config_path) as f:
            cfg = yaml.safe_load(f)
        model = cfg.get("model", model)

    console.print(Panel(
        f"Model: [bold]{model}[/bold]\n"
        "Type [bold]quit[/bold] or [bold]exit[/bold] to leave.\n"
        "Type [bold]/agents[/bold] to list agents.",
        title="💬 Nexus Chat",
        border_style="green",
    ))

    async with Team(model=model) as team:
        # Load agents from config if provided
        for agent_cfg in cfg.get("agents", []):
            team.add_agent(
                name=agent_cfg["name"],
                instructions=agent_cfg.get("instructions", ""),
            )

        while True:
            try:
                user_input = console.input("[bold green]You:[/bold green] ")
            except (EOFError, KeyboardInterrupt):
                console.print("\n[dim]Goodbye![/dim]")
                break

            if user_input.strip().lower() in ("quit", "exit", "q"):
                console.print("[dim]Goodbye![/dim]")
                break

            if user_input.strip() == "/agents":
                for aid, agent in team._agents.items():
                    console.print(f"  • [bold]{agent.name}[/bold] ({aid})")
                continue

            if not user_input.strip():
                continue

            with console.status("[bold green]Thinking..."):
                result = await team.run(user_input)

            console.print(f"[bold blue]Agent:[/bold blue] {result}\n")


if __name__ == "__main__":
    main()
