"""
Doit Agent - CLI Bootstrap & Onboarding Wizard
Entry point for: doit init, doit run, doit update, doit uninstall
"""
from __future__ import annotations

import asyncio
import sys
import os

import click
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt, Confirm
from rich.table import Table
from rich import print as rprint

console = Console()


# ─────────────────────────────────────────────────────────────────────────────
# Helpers
# ─────────────────────────────────────────────────────────────────────────────

def step_ok(msg: str):
    console.print(f"  [green]✓[/green] {msg}")

def step_err(msg: str):
    console.print(f"  [red]✗[/red] {msg}")

def step_info(msg: str):
    console.print(f"  [yellow]→[/yellow] {msg}")


# ─────────────────────────────────────────────────────────────────────────────
# CLI Group
# ─────────────────────────────────────────────────────────────────────────────

@click.group()
def cli():
    """🏋️ Doit — Telegram-Controlled Local Automation Agent"""
    pass


# ─────────────────────────────────────────────────────────────────────────────
# doit init — Full onboarding wizard
# ─────────────────────────────────────────────────────────────────────────────

@cli.command()
def init():
    """Run the onboarding wizard to set up Doit."""
    asyncio.run(_init_wizard())


async def _init_wizard():
    from core.config import (
        BASE_DIR, DATA_DIR, LOG_DIR, PLUGIN_DIR, VERSION, AI_PROVIDERS
    )
    from security.security import get_config, LockFile
    from persistence.database import get_db

    console.print(Panel.fit(
        "[bold cyan]🏋️  DOIT — Telegram Automation Agent[/bold cyan]\n"
        f"[dim]v{VERSION}[/dim]\n\n"
        "Doit runs silently in the background and executes real OS tasks\n"
        "on your behalf — controlled entirely through Telegram.\n\n"
        "[bold]What Doit can do:[/bold]\n"
        "  • Manage files and folders\n"
        "  • Monitor system resources\n"
        "  • Download files, ping hosts, make HTTP requests\n"
        "  • Schedule recurring tasks\n"
        "  • Run safely and recover from crashes automatically\n\n"
        "[bold yellow]Important:[/bold yellow] You will grant full automation permission [bold]once[/bold].\n"
        "No per-task confirmations afterward.",
        title="Welcome"
    ))
    console.print()

    # ── STEP 1: Trust Grant ─────────────────────────────────────────────────
    console.print("[bold]STEP 1 — Trust Grant[/bold]")
    console.print("Doit will operate autonomously on your machine.")
    console.print()
    granted = Confirm.ask(
        "  Grant Doit full automation permission on this laptop?",
        default=False
    )
    if not granted:
        console.print("[red]Setup cancelled. Trust grant is required.[/red]")
        return

    step_ok("Full automation trust granted")
    console.print()

    # ── STEP 2: AI Provider ─────────────────────────────────────────────────
    console.print("[bold]STEP 2 — AI Provider[/bold]")
    console.print("Select your AI provider:")
    console.print()

    provider_list = list(AI_PROVIDERS.keys())
    for i, key in enumerate(provider_list, 1):
        name = AI_PROVIDERS[key]["name"]
        console.print(f"  {i}. {name}")
    console.print()

    while True:
        choice = Prompt.ask("  Enter number", default="1")
        try:
            idx = int(choice) - 1
            if 0 <= idx < len(provider_list):
                break
        except ValueError:
            pass
        console.print("  [red]Invalid choice[/red]")

    provider_key = provider_list[idx]
    provider_info = AI_PROVIDERS[provider_key]
    console.print(f"\n  Selected: [cyan]{provider_info['name']}[/cyan]")
    console.print()

    # Show available models
    base_url = provider_info["base_url"]
    if provider_key == "custom":
        base_url = Prompt.ask("  Enter base URL (OpenAI-compatible)")
        console.print("\n  Available models: (enter manually)")
    else:
        console.print(f"  Available models for [cyan]{provider_info['name']}[/cyan]:")
        models = provider_info["models"]
        for i, m in enumerate(models, 1):
            tag = "[green]FREE[/green]" if m["free"] else "[yellow]PAID[/yellow]"
            console.print(f"    {i}. {m['label']} ({m['id']}) {tag}")
        console.print()

    if provider_key == "custom":
        model_id = Prompt.ask("  Enter model ID")
    else:
        while True:
            mc = Prompt.ask("  Select model number", default="1")
            try:
                mi = int(mc) - 1
                if 0 <= mi < len(models):
                    model_id = models[mi]["id"]
                    break
            except ValueError:
                pass
            console.print("  [red]Invalid[/red]")

    console.print(f"\n  Model: [cyan]{model_id}[/cyan]")
    console.print()

    if provider_key == "ollama":
        api_key = "ollama"
        step_info("Ollama runs locally — no API key needed")
    else:
        api_key = Prompt.ask("  Enter API key", password=True)

    # Validate
    step_info("Testing AI connection...")
    from ai.engine import validate_api_key
    success, msg = await validate_api_key(provider_key, model_id, api_key, base_url or "")
    if success:
        step_ok(f"AI connection verified: {msg}")
    else:
        step_err(f"AI connection failed: {msg}")
        if not Confirm.ask("  Continue anyway?", default=False):
            return

    console.print()

    # ── STEP 3: Telegram ────────────────────────────────────────────────────
    console.print("[bold]STEP 3 — Telegram Setup[/bold]")
    console.print("Create a bot via @BotFather and get your token.")
    console.print("Find your user ID at @userinfobot")
    console.print()

    while True:
        token = Prompt.ask("  Bot token")
        step_info("Validating token...")
        from telegram_bot.bot import validate_bot_token
        ok, info = await validate_bot_token(token)
        if ok:
            step_ok(f"Bot validated: {info}")
            break
        step_err(f"Invalid token: {info}")
        if not Confirm.ask("  Try again?", default=True):
            return

    while True:
        user_id_str = Prompt.ask("  Your Telegram user ID (integer)")
        try:
            user_id = int(user_id_str)
            break
        except ValueError:
            step_err("Must be an integer")

    step_info("Sending test message...")
    from telegram_bot.bot import send_test_message
    ok, msg = await send_test_message(token, user_id)
    if ok:
        step_ok("Test message sent — check Telegram!")
    else:
        step_err(f"Failed to send test message: {msg}")
        if not Confirm.ask("  Continue anyway?", default=False):
            return

    console.print()

    # ── STEP 4: System Preparation ──────────────────────────────────────────
    console.print("[bold]STEP 4 — System Preparation[/bold]")

    # Create directories
    for d, name in [
        (BASE_DIR, "Config directory"),
        (DATA_DIR, "Data directory"),
        (LOG_DIR, "Logs directory"),
        (PLUGIN_DIR, "Plugin directory"),
    ]:
        try:
            d.mkdir(parents=True, exist_ok=True)
            step_ok(f"{name}: {d}")
        except Exception as e:
            step_err(f"{name}: {e}")

    # Init DB
    try:
        db = await get_db()
        step_ok("Database initialized")
    except Exception as e:
        step_err(f"Database: {e}")
        return

    # Save config
    config = get_config()
    config.set("ai_provider", provider_key)
    config.set("ai_model", model_id)
    config.set("ai_api_key", api_key)
    config.set("ai_base_url", base_url or provider_info.get("base_url", ""))
    config.set("telegram_token", token)
    config.set("telegram_user_id", user_id)
    config.set("trust_granted", True)
    config.set("setup_complete", True)
    step_ok("Encrypted config saved")

    # Test outbound connectivity
    step_info("Testing outbound connectivity...")
    try:
        import aiohttp
        async with aiohttp.ClientSession() as sess:
            async with sess.get("https://api.telegram.org", timeout=aiohttp.ClientTimeout(total=5)) as r:
                if r.status < 500:
                    step_ok("Outbound connectivity OK")
                else:
                    step_err(f"Connectivity issue: HTTP {r.status}")
    except Exception as e:
        step_err(f"Connectivity test failed: {e}")

    console.print()

    # ── STEP 5: Auto-Start Service ──────────────────────────────────────────
    console.print("[bold]STEP 5 — Auto-Start Service Installation[/bold]")
    import sys as _sys
    os_name = {"linux": "Linux (systemd)", "darwin": "macOS (LaunchAgent)", "win32": "Windows (Task Scheduler)"}.get(_sys.platform, _sys.platform)
    step_info(f"Detected OS: {os_name}")

    if Confirm.ask("  Install auto-start service?", default=True):
        from services.service import install_service
        ok, msg = install_service()
        if ok:
            step_ok(msg)
        else:
            step_err(msg)
            step_info("You can manually start doit with: doit run")

    console.print()

    # ── STEP 6: Finalization ────────────────────────────────────────────────
    console.print("[bold]STEP 6 — Finalization[/bold]")

    # Summary table
    table = Table(title="Setup Summary")
    table.add_column("Setting", style="cyan")
    table.add_column("Value")
    table.add_row("AI Provider", provider_info["name"])
    table.add_row("AI Model", model_id)
    table.add_row("Telegram Bot", f"User ID: {user_id}")
    table.add_row("Config", str(config.all().get("ai_api_key", "???")[:6] + "..."))
    table.add_row("Data Dir", str(DATA_DIR))
    console.print(table)

    # Write plugin example
    from plugins.manager import write_example_plugin
    await write_example_plugin()
    step_ok(f"Plugin directory ready: {PLUGIN_DIR}")

    # Persist DB config
    await db.config_set("setup_complete", True)
    await db.config_set("version", VERSION)

    console.print()
    console.print(Panel.fit(
        "[bold green]🏋️ Setup complete![/bold green]\n\n"
        "Doit is now configured and ready.\n\n"
        "If auto-start was installed, Doit will start automatically.\n"
        "Otherwise, run: [cyan]doit run[/cyan]\n\n"
        "A confirmation message was (or will be) sent to your Telegram.",
        title="Done"
    ))

    # Start immediately
    if Confirm.ask("\n  Start Doit now in the background?", default=True):
        console.print("[dim]Starting... (close this terminal, Doit keeps running)[/dim]")
        await _run_agent()


# ─────────────────────────────────────────────────────────────────────────────
# doit run — Start the agent
# ─────────────────────────────────────────────────────────────────────────────

@cli.command()
def run():
    """Start the Doit agent (normally called by the OS service)."""
    asyncio.run(_run_agent())


async def _run_agent():
    from core.config import BASE_DIR, VERSION
    from security.security import get_config, LockFile, AuthorizationManager
    from persistence.database import get_db
    from ai.engine import AIEngine
    from telegram_bot.bot import TelegramBot
    from task_engine.engine import get_engine
    from scheduler.scheduler import get_scheduler
    from plugins.manager import get_plugin_manager
    from services.service import service_status
    from supervisor.supervisor import Supervisor, HealthMonitor
    from logging_system.logger import setup_logging, get_db_handler

    # Setup logging
    db_handler = setup_logging()

    import logging
    logger = logging.getLogger("doit.main")

    # Lock file
    lock = LockFile()
    if not lock.acquire():
        console.print("[red]Another Doit instance is already running.[/red]")
        sys.exit(1)

    config = get_config()

    if not config.get("setup_complete"):
        console.print("[red]Doit not configured. Run: doit init[/red]")
        lock.release()
        sys.exit(1)

    logger.info("Doit v%s starting", VERSION)

    # Initialize DB
    db = await get_db()
    await db.audit("agent_start", details={"version": VERSION})

    # Start DB log handler
    if db_handler:
        await db_handler.start()

    # Initialize AI engine
    ai = AIEngine(config.all())

    # Initialize auth manager
    auth = AuthorizationManager(config)

    # Initialize task engine
    engine = get_engine()
    await engine.start()

    # Initialize scheduler
    scheduler = get_scheduler()
    await scheduler.start()

    # Load plugins
    pm = get_plugin_manager()
    loaded_plugins = await pm.discover_and_load()
    if loaded_plugins:
        logger.info("Loaded plugins: %s", loaded_plugins)

    # Create bot
    def safe_mode_callback(mode: bool):
        if mode:
            engine.enter_safe_mode()
        else:
            engine.exit_safe_mode()

    bot = TelegramBot(
        token=config.get("telegram_token"),
        auth=auth,
        ai_engine=ai,
        safe_mode_callback=safe_mode_callback,
    )

    # Health monitor
    health = HealthMonitor(notify_callback=bot.send_message)

    # Setup supervisor
    supervisor = Supervisor()
    supervisor.add_component("telegram_bot", bot.start)
    supervisor.add_component("health_monitor", health.run)

    # Notify user of startup
    async def _startup_notify():
        import asyncio
        await asyncio.sleep(3)  # Wait for bot to connect
        await bot.send_message(
            f"🏋️ Doit v{VERSION} is now active.\n"
            "Send me any task in plain language. Type /help for commands."
        )

    asyncio.create_task(_startup_notify())

    try:
        await supervisor.run()
    finally:
        # Graceful shutdown
        logger.info("Performing graceful shutdown")
        await engine.stop()
        await scheduler.stop()
        await db.audit("agent_stop")
        await db.close()
        if db_handler:
            await db_handler.stop()
        lock.release()
        logger.info("Doit stopped cleanly")


# ─────────────────────────────────────────────────────────────────────────────
# doit update — Check and apply updates
# ─────────────────────────────────────────────────────────────────────────────

@cli.command()
def update():
    """Check for updates and upgrade doit-agent."""
    asyncio.run(_do_update())


async def _do_update():
    from updates.updater import check_for_updates, perform_update

    console.print("[bold]Checking for updates...[/bold]")
    available, current, latest = await check_for_updates()

    if not available:
        console.print(f"[green]Already up to date: v{current}[/green]")
        return

    console.print(f"Update available: [cyan]v{current}[/cyan] → [green]v{latest}[/green]")
    if Confirm.ask("Update now?", default=True):
        console.print("Updating...")
        ok, msg = await perform_update()
        if ok:
            console.print(f"[green]{msg}[/green]")
        else:
            console.print(f"[red]{msg}[/red]")


# ─────────────────────────────────────────────────────────────────────────────
# doit status — Quick status check
# ─────────────────────────────────────────────────────────────────────────────

@cli.command()
def status():
    """Check doit agent status."""
    from services.service import service_status
    running, status_str = service_status()
    icon = "🟢" if running else "🔴"
    console.print(f"{icon} Doit service: {status_str}")


# ─────────────────────────────────────────────────────────────────────────────
# doit uninstall — Remove service and optionally data
# ─────────────────────────────────────────────────────────────────────────────

@cli.command()
def uninstall():
    """Uninstall Doit service and optionally clean up data."""
    from services.service import uninstall_service
    ok, msg = uninstall_service()
    if ok:
        console.print(f"[green]✓ {msg}[/green]")
    else:
        console.print(f"[red]✗ {msg}[/red]")

    if Confirm.ask("Also delete all Doit data and config?", default=False):
        from core.config import BASE_DIR
        import shutil
        shutil.rmtree(str(BASE_DIR), ignore_errors=True)
        console.print("[green]✓ Data removed[/green]")

    console.print("Doit uninstalled.")


if __name__ == "__main__":
    cli()
