"""
Open-Sable CLI - Command Line Interface

Provides commands for managing the gateway, agents, and channels.
"""

import click
import asyncio
import sys
from pathlib import Path
import logging

logger = logging.getLogger(__name__)


@click.group()
@click.version_option(version="0.2.0")
def cli():
    """Open-Sable - Lightweight AI Agent Platform"""
    pass


@cli.command()
@click.option("--host", default="127.0.0.1", help="Gateway host")
@click.option("--port", default=18789, help="Gateway port")
@click.option("--verbose", is_flag=True, help="Enable verbose logging")
def gateway(host, port, verbose):
    """Start the Gateway control plane"""
    if verbose:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig(level=logging.INFO)

    click.echo("🚀 Starting Open-Sable Gateway...")
    click.echo(f"   Host: {host}")
    click.echo(f"   Port: {port}")
    click.echo(f"   Dashboard: http://{host}:{port}")
    click.echo(f"   WebSocket: ws://{host}:{port}/ws")
    click.echo()

    try:
        from core.config import load_config
        from core.gateway import Gateway

        config = load_config()
        gateway_instance = Gateway(config)

        asyncio.run(gateway_instance.start(host, port))

    except KeyboardInterrupt:
        click.echo("\n👋 Gateway stopped by user")
    except Exception as e:
        click.echo(f"❌ Error starting gateway: {e}", err=True)
        sys.exit(1)


@cli.command()
@click.argument("message", required=False)
@click.option(
    "--thinking", default="medium", help="Thinking level (off|minimal|low|medium|high|xhigh)"
)
@click.option("--model", help="Override model")
def agent(message, thinking, model):
    """Send a message directly to the agent"""
    try:
        from core.config import load_config
        from core.agent import SableAgent

        config = load_config()
        agent_instance = SableAgent(config)

        async def run_agent():
            await agent_instance.initialize()

            if message:
                # Single message mode
                response = await agent_instance.run(message)
                click.echo(response)
            else:
                # Interactive mode
                click.echo("🤖 Open-Sable Agent (type 'exit' to quit)")
                click.echo()

                while True:
                    try:
                        user_input = click.prompt("You", type=str)

                        if user_input.lower() in ["exit", "quit", "q"]:
                            break

                        response = await agent_instance.run(user_input)
                        click.echo(f"\nSable: {response}\n")

                    except (EOFError, KeyboardInterrupt):
                        break

                click.echo("\n👋 Goodbye!")

        asyncio.run(run_agent())

    except Exception as e:
        click.echo(f"❌ Error: {e}", err=True)
        sys.exit(1)


@cli.command()
def onboard():
    """Interactive setup wizard"""
    click.echo("🎉 Welcome to Open-Sable!")
    click.echo()
    click.echo("This wizard will help you set up your AI agent.")
    click.echo()

    # Check for existing .env
    env_file = Path(".env")
    if env_file.exists():
        if not click.confirm("Found existing .env file. Overwrite?"):
            click.echo("Keeping existing configuration.")
            return

    click.echo("📝 Configuration")
    click.echo()

    # Agent name
    agent_name = click.prompt("Agent name", default="Sable")

    # LLM configuration
    click.echo("\n🤖 AI Model Configuration")
    default_model = click.prompt("Default model", default="llama3.1:8b")

    # Telegram
    click.echo("\n📱 Telegram Bot (optional)")
    enable_telegram = click.confirm("Enable Telegram bot?", default=True)
    telegram_token = ""
    if enable_telegram:
        telegram_token = click.prompt("Telegram bot token (from @BotFather)")

    # Discord
    click.echo("\n💬 Discord Bot (optional)")
    enable_discord = click.confirm("Enable Discord bot?", default=False)
    discord_token = ""
    if enable_discord:
        discord_token = click.prompt("Discord bot token")

    # WhatsApp
    click.echo("\n💚 WhatsApp (optional)")
    enable_whatsapp = click.confirm("Enable WhatsApp?", default=False)

    # Voice
    click.echo("\n🎤 Voice Support (optional)")
    enable_voice = click.confirm("Enable voice support?", default=False)
    tts_provider = "local"
    if enable_voice:
        tts_provider = click.prompt(
            "TTS provider", type=click.Choice(["local", "elevenlabs", "openai"]), default="local"
        )

    # Generate .env file
    env_content = f"""# Open-Sable Configuration
# Generated by onboard wizard

# Agent settings
AGENT_NAME={agent_name}
DEFAULT_MODEL={default_model}
AUTO_SELECT_MODEL=true

# Telegram
TELEGRAM_BOT_TOKEN={telegram_token if enable_telegram else ''}
TELEGRAM_USERBOT_ENABLED=false

# Discord
DISCORD_BOT_TOKEN={discord_token if enable_discord else ''}

# WhatsApp
WHATSAPP_ENABLED={str(enable_whatsapp).lower()}

# Voice
VOICE_ENABLED={str(enable_voice).lower()}
TTS_PROVIDER={tts_provider}
STT_PROVIDER=local

# Gateway
GATEWAY_HOST=127.0.0.1
GATEWAY_PORT=18789

# Skills
EMAIL_ENABLED=false
CALENDAR_ENABLED=false
BROWSER_ENABLED=true
"""

    with open(".env", "w") as f:
        f.write(env_content)

    click.echo("\n✅ Configuration saved to .env")
    click.echo()
    click.echo("🎯 Next steps:")
    click.echo("   1. Install dependencies: pip install -r requirements.txt")
    click.echo("   2. Start gateway: sable gateway")
    click.echo("   3. Test agent: sable agent")
    click.echo()
    click.echo("📚 Documentation: https://github.com/yourusername/Open-Sable")


@cli.command()
def doctor():
    """Run system diagnostics"""
    click.echo("🔍 Open-Sable Doctor - System Diagnostics")
    click.echo()

    checks = []

    # Check Python version
    import sys

    py_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
    py_ok = sys.version_info >= (3, 11)
    checks.append(("Python version", py_version, py_ok))

    # Check dependencies
    deps = [
        ("ollama", "Ollama SDK"),
        ("chromadb", "ChromaDB"),
        ("aiogram", "Telegram"),
        ("discord", "Discord"),
        ("fastapi", "Gateway"),
    ]

    for module, name in deps:
        try:
            __import__(module)
            checks.append((f"{name} installed", "✓", True))
        except ImportError:
            checks.append((f"{name} installed", "✗", False))

    # Check .env file
    env_exists = Path(".env").exists()
    checks.append((".env file", "✓" if env_exists else "✗", env_exists))

    # Check Ollama
    try:
        import httpx

        response = httpx.get("http://localhost:11434/api/tags", timeout=2)
        ollama_ok = response.status_code == 200
        checks.append(("Ollama running", "✓" if ollama_ok else "✗", ollama_ok))
    except:
        checks.append(("Ollama running", "✗", False))

    # Print results
    for check, status, ok in checks:
        color = "green" if ok else "red"
        click.echo(f"  {click.style(status, fg=color)} {check}")

    click.echo()

    # Summary
    passed = sum(1 for _, _, ok in checks if ok)
    total = len(checks)

    if passed == total:
        click.echo(click.style(f"✅ All checks passed ({passed}/{total})", fg="green"))
    else:
        click.echo(click.style(f"⚠️  Some checks failed ({passed}/{total})", fg="yellow"))
        click.echo()
        click.echo("💡 To fix issues:")
        click.echo("   • Install dependencies: pip install -r requirements.txt")
        click.echo("   • Create .env file: sable onboard")
        click.echo("   • Start Ollama: ollama serve")


@cli.command()
@click.argument("channel", type=click.Choice(["telegram", "discord", "whatsapp"]))
def login(channel):
    """Authenticate a messaging channel"""
    click.echo(f"🔐 Authenticating {channel.title()}...")
    click.echo()

    if channel == "whatsapp":
        click.echo("WhatsApp authentication will show a QR code.")
        click.echo("Scan it with your phone to link your account.")
        click.echo()

        try:
            from interfaces.whatsapp_bot import WhatsAppInterface
            from core.config import load_config

            config = load_config()
            whatsapp = WhatsAppInterface(None, config)

            asyncio.run(whatsapp.start())

        except Exception as e:
            click.echo(f"❌ Error: {e}", err=True)
            sys.exit(1)
    else:
        click.echo(f"{channel.title()} uses token authentication.")
        click.echo("Add your token to .env file:")
        click.echo(f"   {channel.upper()}_BOT_TOKEN=your_token_here")


@cli.command()
@click.option("--format", type=click.Choice(["table", "json"]), default="table")
def sessions(format):
    """List active sessions"""
    try:
        from core.sessions import SessionManager
        from core.config import load_config

        config = load_config()
        manager = SessionManager(config)
        manager.load_from_disk()

        sessions_list = manager.get_all_sessions()

        if format == "json":
            import json

            data = [s.to_dict() for s in sessions_list]
            click.echo(json.dumps(data, indent=2))
        else:
            if not sessions_list:
                click.echo("No active sessions.")
                return

            click.echo(f"\n📊 Active Sessions ({len(sessions_list)}):\n")

            for session in sessions_list:
                click.echo(f"  ID: {session.id[:12]}...")
                click.echo(f"  Channel: {session.channel}")
                click.echo(f"  Messages: {session.message_count}")
                click.echo(f"  Model: {session.config.model or 'default'}")
                click.echo()

    except Exception as e:
        click.echo(f"❌ Error: {e}", err=True)
        sys.exit(1)


# ── Connectome Brain Monitor ─────────────────────────────────────────────────

@cli.command()
@click.option("--host", default="127.0.0.1", help="Gateway host")
@click.option("--port", default=18789, help="Gateway port")
@click.option("--watch", "-w", is_flag=True, help="Live refresh every 3s")
@click.option("--json", "as_json", is_flag=True, help="Raw JSON output")
def brain(host, port, watch, as_json):
    """Monitor the connectome neural colony in real-time"""
    import json as _json
    import time
    try:
        import urllib.request
    except ImportError:
        click.echo("❌ urllib not available", err=True)
        sys.exit(1)

    url = f"http://{host}:{port}/api/connectome"

    def _fetch():
        try:
            req = urllib.request.Request(url)
            with urllib.request.urlopen(req, timeout=5) as resp:
                return _json.loads(resp.read())
        except Exception as e:
            return {"error": str(e)}

    def _render(data):
        if "error" in data:
            click.echo(f"  ⚠  {data['error']}")
            return

        stats = data.get("stats", {})
        nodes = data.get("nodes", [])
        edges = data.get("edges", [])

        # Header
        gen = stats.get("generation", 0)
        mutated = stats.get("mutated_connections", 0)
        max_drift = stats.get("max_drift", 0)
        total_fire = stats.get("total_firings", 0)
        total_prop = stats.get("total_propagations", 0)

        click.echo(f"  Gen {click.style(str(gen), fg='magenta', bold=True)}"
                   f"  │  Mutations {click.style(str(mutated), fg='yellow')}/{len(edges)}"
                   f"  │  Max drift {click.style(f'{max_drift:.4f}', fg='red' if max_drift > 0.3 else 'green')}"
                   f"  │  Fires {total_fire}  │  Propagations {total_prop}")
        click.echo()

        # Region table
        click.echo("  ┌──────┬──────────────────┬───────────┬───────┬───────┐")
        click.echo("  │ Region │ Module           │ Activation│ Fires │ Thr   │")
        click.echo("  ├──────┼──────────────────┼───────────┼───────┼───────┤")
        for n in sorted(nodes, key=lambda x: x.get("activation", 0), reverse=True):
            act = n.get("activation", 0)
            bar_len = int(act * 10)
            bar = "█" * bar_len + "░" * (10 - bar_len)
            act_color = "magenta" if act > 0.5 else ("cyan" if act > 0.1 else "white")
            region = n.get("region", "?").ljust(4)
            module = n.get("module", "?").ljust(16)
            fires = str(n.get("fire_count", 0)).rjust(5)
            thr = f"{n.get('threshold', 0):.2f}"
            click.echo(f"  │ {click.style(region, fg='cyan', bold=True)}"
                       f" │ {module}"
                       f" │ {click.style(bar, fg=act_color)} "
                       f"│{fires} │ {thr} │")
        click.echo("  └──────┴──────────────────┴───────────┴───────┴───────┘")
        click.echo()

        # Top connections by weight
        sorted_edges = sorted(edges, key=lambda e: e.get("weight", 0), reverse=True)
        click.echo("  Top connections:")
        for e in sorted_edges[:12]:
            src = e.get("src", "?")
            dst = e.get("dst", "?")
            w = e.get("weight", 0)
            drift = e.get("drift", 0)
            muts = e.get("mutations", 0)
            w_bar = "▓" * int(w * 15) + "░" * (15 - int(w * 15))
            drift_s = ""
            if abs(drift) > 0.005:
                d_color = "yellow" if abs(drift) < 0.2 else "red"
                sign = "+" if drift > 0 else ""
                drift_s = click.style(f" Δ{sign}{drift:.3f}", fg=d_color)
            mut_s = click.style(f" m{muts}", fg="yellow") if muts > 0 else ""
            click.echo(f"    {click.style(src.ljust(4), fg='magenta')}"
                       f" → {click.style(dst.ljust(4), fg='cyan')}"
                       f"  {w_bar} {w:.3f}{drift_s}{mut_s}")

    def _display():
        data = _fetch()
        if as_json:
            click.echo(_json.dumps(data, indent=2))
            return
        click.clear()
        ts = time.strftime("%H:%M:%S")
        click.echo()
        click.echo(f"  🧠 {click.style('CONNECTOME NEURAL COLONY', bold=True)}"
                   f"  {click.style(f'[{ts}]', fg='bright_black')}"
                   f"  {click.style(url, fg='bright_black')}")
        click.echo(f"  {click.style('FlyWire FAFB v783,  Drosophila melanogaster connectome', fg='bright_black')}")
        click.echo()
        _render(data)
        if watch:
            click.echo(f"\n  {click.style('Ctrl+C to exit  •  Refreshing every 3s', fg='bright_black')}")

    try:
        if watch:
            while True:
                _display()
                time.sleep(3)
        else:
            _display()
    except KeyboardInterrupt:
        click.echo("\n  Stopped.")


if __name__ == "__main__":
    cli()
