"""CLI entry point for meeting-helper."""

from __future__ import annotations

import json
import os
import sys
import time
from pathlib import Path

import click

from meeting_helper.config import (
    CLAUDE_MODELS,
    CONFIG_FILE,
    LOG_FILE,
    Config,
    get_config,
)
from meeting_helper.daemon import is_process_running, kill_existing, read_meta, read_pid


@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    """Meeting Helper — AI meeting assistant for macOS."""
    if ctx.invoked_subcommand is None:
        ctx.invoke(start)


@cli.command()
@click.option("--foreground", "-f", is_flag=True, help="Run daemon in foreground (no fork)")
def start(foreground):
    """Start the daemon (auto-detects meetings, records, transcribes)."""
    config = get_config()

    if not config.anthropic_api_key:
        click.echo("No Anthropic API key configured. Run: meeting-helper setup")
        sys.exit(1)

    # Kill existing daemon if running
    existing_pid = read_pid()
    if existing_pid and is_process_running(existing_pid):
        click.echo(f"Daemon already running (pid={existing_pid}). Stopping it first...")
        kill_existing()
        time.sleep(0.5)

    app_config = config.to_app_config()
    click.echo(f"Starting daemon on port {app_config.port}...")

    if foreground:
        _run_foreground(app_config)
    else:
        from meeting_helper.daemon import run_daemon
        run_daemon(app_config)


def _run_foreground(config):
    """Run daemon without forking (for debugging)."""
    import asyncio
    import logging
    import signal

    from meeting_helper.buffer import SentenceBuffer
    from meeting_helper.daemon import write_meta, write_pid_file, remove_pid_file, remove_meta
    from meeting_helper.hotkeys import start_hotkey_listener
    from meeting_helper.server.app import create_app
    from meeting_helper.session import MeetingSession
    from meeting_helper.state import state

    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    )
    logger = logging.getLogger("meeting_helper")

    write_pid_file()

    state.started_at = time.time()
    state.sentence_buffer = SentenceBuffer(max_sentences=50)
    state.system_prompt = config.system_prompt

    def on_meeting_start(info):
        state.status = "listening"
        state.meeting_info = info
        state.session_active = True
        logger.info("Meeting started: %s (%s)", info.app_name, info.meeting_name or "unnamed")

    def on_meeting_end(saved_path):
        state.status = "idle"
        state.meeting_info = None
        state.session_active = False
        state.conversation_history.clear()
        logger.info("Meeting ended. Recording: %s", saved_path)

    session = MeetingSession(
        config=config,
        sentence_buffer=state.sentence_buffer,
        on_meeting_start=on_meeting_start,
        on_meeting_end=on_meeting_end,
    )
    session.start()
    write_meta(config, transcriber_name="pending")
    start_hotkey_listener(config)

    # Auto-launch overlay (shares proc ref with hotkey module)
    from meeting_helper.daemon import _launch_overlay
    _launch_overlay(config)

    async def _main():
        import aiohttp.web as web

        loop = asyncio.get_running_loop()
        state.asyncio_loop = loop
        state.shutdown_event = asyncio.Event()

        app = create_app(config)
        runner = web.AppRunner(app)
        await runner.setup()
        site = web.TCPSite(runner, "0.0.0.0", config.port)
        await site.start()
        logger.info("Server on 0.0.0.0:%d", config.port)

        try:
            await state.shutdown_event.wait()
        except asyncio.CancelledError:
            pass
        finally:
            await runner.cleanup()

    try:
        asyncio.run(_main())
    except KeyboardInterrupt:
        click.echo("\nShutting down...")
    finally:
        session.stop()
        remove_pid_file()
        remove_meta()


@cli.command()
def stop():
    """Stop the running daemon."""
    if kill_existing():
        click.echo("Daemon stopped.")
    else:
        click.echo("No daemon running.")


@cli.command()
def status():
    """Show daemon status."""
    pid = read_pid()
    if pid and is_process_running(pid):
        meta = read_meta()
        click.echo(f"Daemon running (pid={pid})")
        if meta:
            port = meta.get("port", "?")
            model = meta.get("claude_model", "?")
            transcriber = meta.get("transcriber", "?")
            repos = meta.get("repos", [])
            click.echo(f"  Port: {port}")
            click.echo(f"  Model: {model}")
            click.echo(f"  Transcriber: {transcriber}")
            click.echo(f"  Repos: {len(repos)}")
            started = meta.get("started_at", 0)
            if started:
                uptime = int(time.time() - started)
                m, s = divmod(uptime, 60)
                h, m = divmod(m, 60)
                click.echo(f"  Uptime: {h}h {m}m {s}s")

        # Try health endpoint
        try:
            import urllib.request
            port = (meta or {}).get("port", 7891)
            req = urllib.request.Request(f"http://127.0.0.1:{port}/health")
            with urllib.request.urlopen(req, timeout=2) as resp:
                data = json.loads(resp.read().decode())
            meeting = data.get("meeting", "")
            if meeting:
                click.echo(f"  Meeting: {meeting}")
            click.echo(f"  Session: {'active' if data.get('session_active') else 'idle'}")
        except Exception:
            pass
    else:
        click.echo("Daemon not running.")


@cli.command()
def setup():
    """Interactive setup wizard."""
    config = get_config()

    click.echo("\n  Meeting Helper Setup\n")

    # Anthropic key
    current_key = config.anthropic_api_key
    masked = f"...{current_key[-8:]}" if len(current_key) > 8 else "(not set)"
    click.echo(f"  Current Anthropic key: {masked}")
    key = click.prompt("  Anthropic API key (Enter to keep)", default="", show_default=False)
    if key.strip():
        config.anthropic_api_key = key.strip()

    # Deepgram key (optional)
    current_dg = config.deepgram_api_key
    masked_dg = f"...{current_dg[-8:]}" if len(current_dg) > 8 else "(not set)"
    click.echo(f"\n  Current Deepgram key: {masked_dg}")
    dg_key = click.prompt("  Deepgram API key (Enter to skip)", default="", show_default=False)
    if dg_key.strip():
        config.deepgram_api_key = dg_key.strip()

    # Claude model
    click.echo(f"\n  Current model: {config._data.get('claude_model', 'sonnet')}")
    models = list(CLAUDE_MODELS.keys())
    for i, m in enumerate(models):
        click.echo(f"    {i + 1}. {m} ({CLAUDE_MODELS[m]})")
    choice = click.prompt("  Select model (1-3, Enter to keep)", default="", show_default=False)
    if choice.strip() and choice.strip().isdigit():
        idx = int(choice.strip()) - 1
        if 0 <= idx < len(models):
            config.claude_model = models[idx]

    # Recordings dir
    click.echo(f"\n  Recordings dir: {config.recordings_dir}")
    rec_dir = click.prompt("  Recordings directory (Enter to keep)", default="", show_default=False)
    if rec_dir.strip():
        config.recordings_dir = rec_dir.strip()

    config.setup_complete = True
    config.save()

    # Pre-download Whisper model so first meeting doesn't stall
    click.echo("\n  Downloading Whisper transcription model (runs locally, one-time download)...")
    try:
        import certifi, os
        os.environ.setdefault("SSL_CERT_FILE", certifi.where())
        os.environ.setdefault("REQUESTS_CA_BUNDLE", certifi.where())
        from faster_whisper import WhisperModel
        WhisperModel("base", device="cpu", compute_type="int8")
        click.echo("  Whisper model ready.")
    except Exception as exc:
        click.echo(f"  Warning: could not download Whisper model: {exc}")
        click.echo("  Run manually: python3 -c \"from faster_whisper import WhisperModel; WhisperModel('base', device='cpu', compute_type='int8')\"")

    click.echo("\n  Setup complete! Run 'meeting-helper start' to begin.\n")


@cli.command()
def gui():
    """Open the desktop GUI (Material Design 3, launches in background)."""
    import subprocess

    log_path = Path.home() / ".meeting-helper-gui.log"
    with open(log_path, "a") as log_fh:
        subprocess.Popen(
            [sys.executable, "-m", "meeting_helper.flet_gui"],
            stdout=log_fh,
            stderr=log_fh,
            stdin=subprocess.DEVNULL,
            start_new_session=True,
        )
    click.echo("GUI launched.")


@cli.command()
def version():
    """Show current version and check/install latest from PyPI."""
    import subprocess
    import ssl
    import urllib.request
    import urllib.error
    from meeting_helper import __version__

    # Version check only — no sensitive data, skip SSL verification
    ssl_ctx = ssl._create_unverified_context()

    click.echo(f"  meeting-helper v{__version__}")
    click.echo("  Checking for updates…")

    try:
        req = urllib.request.Request(
            "https://pypi.org/pypi/meeting-helper/json",
            headers={"User-Agent": "meeting-helper"},
        )
        with urllib.request.urlopen(req, timeout=8, context=ssl_ctx) as resp:
            latest = json.loads(resp.read())["info"]["version"]
    except Exception as exc:
        click.echo(f"  Could not reach PyPI: {exc}", err=True)
        return

    if latest == __version__:
        click.echo(f"  Already on latest version (v{__version__})")
        return

    click.echo(f"  Update available: v{__version__} → v{latest}")
    click.echo("  Updating…")
    result = subprocess.run(
        ["pipx", "upgrade", "--pip-args=--no-cache-dir", "meeting-helper"],
        capture_output=True, text=True,
    )

    if result.returncode != 0:
        result = subprocess.run(
            ["pipx", "install", "--force", "--pip-args=--no-cache-dir", "meeting-helper"],
            capture_output=True, text=True,
        )

    if result.returncode == 0:
        click.echo(f"  Updated: v{__version__} → v{latest}")
    else:
        click.echo("  Update failed. Try manually: pipx upgrade meeting-helper", err=True)
        if result.stderr.strip():
            click.echo(f"  {result.stderr.strip()}", err=True)


@cli.command()
def autostart():
    """Install or remove meeting-helper as a login item (auto-start on login)."""
    import subprocess
    plist_dir = Path.home() / "Library" / "LaunchAgents"
    plist_path = plist_dir / "com.meeting-helper.daemon.plist"

    exe = subprocess.run(["which", "meeting-helper"], capture_output=True, text=True).stdout.strip()
    if not exe:
        click.echo("  meeting-helper not found in PATH. Install it first.")
        return

    if plist_path.exists():
        # Already installed — ask to remove
        click.echo(f"  Auto-start is currently ENABLED ({plist_path})")
        if click.confirm("  Disable auto-start?"):
            subprocess.run(["launchctl", "unload", str(plist_path)], capture_output=True)
            plist_path.unlink()
            click.echo("  Auto-start disabled.")
        return

    plist_dir.mkdir(parents=True, exist_ok=True)
    plist_content = f"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.meeting-helper.daemon</string>
    <key>ProgramArguments</key>
    <array>
        <string>{exe}</string>
        <string>start</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <false/>
    <key>StandardOutPath</key>
    <string>{LOG_FILE}</string>
    <key>StandardErrorPath</key>
    <string>{LOG_FILE}</string>
</dict>
</plist>"""
    plist_path.write_text(plist_content)
    result = subprocess.run(["launchctl", "load", str(plist_path)], capture_output=True, text=True)
    if result.returncode == 0:
        click.echo(f"  Auto-start enabled. meeting-helper will start automatically on login.")
        click.echo(f"  Run 'meeting-helper autostart' again to disable.")
    else:
        click.echo(f"  Failed to register: {result.stderr.strip()}")


@cli.command()
def logs():
    """Tail the daemon log file."""
    if not LOG_FILE.exists():
        click.echo("No log file found.")
        return

    click.echo(f"Tailing {LOG_FILE}...\n")
    try:
        import subprocess
        subprocess.run(["tail", "-f", "-n", "50", str(LOG_FILE)])
    except KeyboardInterrupt:
        pass
