"""MidOS MCP CLI — install, configure, and run the MCP server."""

import json
import sys
from pathlib import Path

import click

from midos_mcp import __version__
from midos_mcp.config import (
    MIDOS_ROOT,
    KNOWLEDGE_DIR,
    SKILLS_DIR,
    EUREKA_DIR,
    TRUTH_DIR,
    CHUNKS_DIR,
    DEFAULT_HOST,
    DEFAULT_PORT,
    CONFIG_DIR,
    API_KEYS_FILE,
)


# ============================================================================
# CLIENT CONFIG TEMPLATES
# ============================================================================


def _server_command() -> list[str]:
    """Return the command to start the MidOS MCP server."""
    return ["python", "-m", "midos_mcp", "serve"]


def _make_stdio_config() -> dict:
    """Base stdio config for MCP clients."""
    cfg = {
        "command": "python",
        "args": ["-m", "midos_mcp", "serve"],
    }
    # Only add env hint if MIDOS_ROOT was explicitly set
    if "MIDOS_ROOT" in __import__("os").environ:
        cfg["env"] = {"MIDOS_ROOT": str(MIDOS_ROOT)}
    return cfg


def _make_http_config(host: str = "127.0.0.1", port: int = 8419) -> dict:
    """Base HTTP config for MCP clients."""
    return {
        "url": f"http://{host}:{port}/mcp",
        "transport": "streamable-http",
    }


CLIENT_TEMPLATES = {
    "claude": {
        "name": "Claude Desktop / Claude Code",
        "file": "claude_desktop_config.json (or .mcp.json)",
        "generate": lambda: {
            "mcpServers": {
                "midos": _make_stdio_config(),
            }
        },
    },
    "cursor": {
        "name": "Cursor IDE",
        "file": ".cursor/mcp.json",
        "generate": lambda: {
            "mcpServers": {
                "midos": _make_stdio_config(),
            }
        },
    },
    "cline": {
        "name": "Cline (VS Code Extension)",
        "file": "cline_mcp_settings.json",
        "generate": lambda: {
            "mcpServers": {
                "midos": _make_stdio_config(),
            }
        },
    },
    "windsurf": {
        "name": "Windsurf IDE",
        "file": "~/.codeium/windsurf/mcp_config.json",
        "generate": lambda: {
            "mcpServers": {
                "midos": _make_stdio_config(),
            }
        },
    },
    "continue": {
        "name": "Continue.dev (VS Code)",
        "file": "~/.continue/config.json",
        "generate": lambda: {
            "mcpServers": [
                {
                    "name": "midos",
                    "command": "python",
                    "args": ["-m", "midos_mcp", "serve"],
                }
            ]
        },
    },
    "zed": {
        "name": "Zed Editor",
        "file": "~/.config/zed/settings.json",
        "generate": lambda: {
            "context_servers": {
                "midos": {
                    "command": {
                        "path": "python",
                        "args": ["-m", "midos_mcp", "serve"],
                    }
                }
            }
        },
    },
    "opencode": {
        "name": "OpenCode",
        "file": "opencode.json (MCP section)",
        "generate": lambda: {
            "mcpServers": {
                "midos": {
                    "command": "python",
                    "args": ["-m", "midos_mcp", "serve", "--sse", "--port", "8419"],
                },
            }
        },
    },
    "http": {
        "name": "Any HTTP client (generic)",
        "file": "N/A — use URL directly",
        "generate": lambda: _make_http_config(),
    },
}


# ============================================================================
# CLI GROUP
# ============================================================================


@click.group()
@click.version_option(__version__, prog_name="midos-mcp")
def cli():
    """MidOS MCP Server — Knowledge, Skills, and Research as MCP tools."""
    pass


# ============================================================================
# SERVE
# ============================================================================


@cli.command()
@click.option(
    "--http", "transport", flag_value="http", help="Streamable HTTP transport"
)
@click.option("--sse", "transport", flag_value="sse", help="Legacy SSE transport")
@click.option(
    "--stdio",
    "transport",
    flag_value="stdio",
    default=True,
    help="stdio transport (default)",
)
@click.option("--host", default=DEFAULT_HOST, show_default=True, help="HTTP bind host")
@click.option(
    "--port", default=DEFAULT_PORT, type=int, show_default=True, help="HTTP bind port"
)
def serve(transport, host, port):
    """Start the MidOS MCP server.

    Default transport is stdio (for Claude Code, Cursor, etc.).
    Use --http for Streamable HTTP or --sse for legacy clients.
    """
    # Validate MidOS root
    if not KNOWLEDGE_DIR.is_dir():
        click.echo(f"Error: Knowledge directory not found at {KNOWLEDGE_DIR}", err=True)
        click.echo(
            f"Set MIDOS_ROOT env var to point to your MidOS installation.", err=True
        )
        sys.exit(1)

    # Import the actual server (deferred to avoid slow import on --help)
    try:
        sys.path.insert(0, str(MIDOS_ROOT))
        from modules.m90_mcp_server.midos_mcp import mcp, main as server_main
    except ImportError as e:
        click.echo(f"Error importing MidOS server: {e}", err=True)
        click.echo(f"MIDOS_ROOT={MIDOS_ROOT}", err=True)
        sys.exit(1)

    click.echo(f"MidOS MCP Server v{__version__}")
    click.echo(f"Root: {MIDOS_ROOT}")

    if transport == "http":
        click.echo(f"Transport: streamable-http on {host}:{port}")
        click.echo(f"Endpoint: http://{host}:{port}/mcp")
        mcp.run(transport="streamable-http", host=host, port=port, stateless_http=True)
    elif transport == "sse":
        click.echo(f"Transport: SSE on {host}:{port}")
        click.echo(f"Endpoint: http://{host}:{port}/sse")
        mcp.run(transport="sse", host=host, port=port)
    else:
        click.echo("Transport: stdio")
        mcp.run()


# ============================================================================
# CONFIG
# ============================================================================


@cli.command()
@click.option(
    "--generate",
    "client",
    type=click.Choice(list(CLIENT_TEMPLATES.keys())),
    required=True,
    help="Generate config for this MCP client.",
)
@click.option(
    "--output", "-o", type=click.Path(), help="Write to file instead of stdout"
)
def config(client, output):
    """Generate MCP config for AI clients.

    Outputs a JSON snippet ready to paste into the client's config file.
    """
    template = CLIENT_TEMPLATES[client]
    config_data = template["generate"]()

    formatted = json.dumps(config_data, indent=2, ensure_ascii=False)

    if output:
        Path(output).write_text(formatted, encoding="utf-8")
        click.echo(f"Config written to {output}")
    else:
        click.echo(f"# {template['name']}")
        click.echo(f"# File: {template['file']}")
        click.echo(f"# Paste this into your config:\n")
        click.echo(formatted)


@cli.command("config-list")
def config_list():
    """List all supported MCP clients."""
    click.echo(f"Supported clients ({len(CLIENT_TEMPLATES)}):\n")
    for key, tmpl in CLIENT_TEMPLATES.items():
        click.echo(f"  {key:12s}  {tmpl['name']}")
        click.echo(f"  {'':12s}  Config: {tmpl['file']}")
        click.echo()
    click.echo("Usage: midos-mcp config --generate <client>")


# ============================================================================
# HEALTH
# ============================================================================


@cli.command()
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
def health(as_json):
    """Check MidOS server health and knowledge base status."""
    checks = {}

    # Knowledge base
    chunks_count = len(list(CHUNKS_DIR.glob("*.md"))) if CHUNKS_DIR.is_dir() else 0
    skills_count = len(list(SKILLS_DIR.glob("*.md"))) if SKILLS_DIR.is_dir() else 0
    eureka_count = len(list(EUREKA_DIR.glob("*.md"))) if EUREKA_DIR.is_dir() else 0
    truth_count = len(list(TRUTH_DIR.glob("*.md"))) if TRUTH_DIR.is_dir() else 0

    checks["knowledge"] = {
        "status": "ok" if chunks_count > 0 else "missing",
        "chunks": chunks_count,
        "skills": skills_count,
        "eureka": eureka_count,
        "truth": truth_count,
    }

    # Config
    checks["config"] = {
        "midos_root": str(MIDOS_ROOT),
        "root_exists": MIDOS_ROOT.is_dir(),
        "api_keys_file": API_KEYS_FILE.exists(),
    }

    # Vector store
    lance_path = KNOWLEDGE_DIR / "memory" / "midos_knowledge.lance"
    checks["vector_store"] = {
        "status": "ok" if lance_path.is_dir() else "not_found",
        "path": str(lance_path),
    }

    # hive_commons
    try:
        import hive_commons  # noqa: F401

        checks["hive_commons"] = {"status": "available"}
    except ImportError:
        checks["hive_commons"] = {
            "status": "not_installed",
            "note": "pip install hive-commons",
        }

    # FastMCP
    try:
        import fastmcp

        checks["fastmcp"] = {
            "status": "ok",
            "version": getattr(fastmcp, "__version__", "unknown"),
        }
    except ImportError:
        checks["fastmcp"] = {"status": "missing"}

    overall = (
        "healthy"
        if checks["knowledge"]["status"] == "ok" and checks["fastmcp"]["status"] == "ok"
        else "degraded"
    )

    result = {
        "status": overall,
        "version": __version__,
        "checks": checks,
    }

    if as_json:
        click.echo(json.dumps(result, indent=2))
    else:
        status_icon = "OK" if overall == "healthy" else "DEGRADED"
        click.echo(f"MidOS MCP v{__version__} — {status_icon}\n")
        click.echo(f"Root:       {MIDOS_ROOT}")
        click.echo(
            f"Knowledge:  {chunks_count} chunks, {skills_count} skills, {eureka_count} EUREKA, {truth_count} truth"
        )
        click.echo(f"Vector DB:  {checks['vector_store']['status']}")
        click.echo(f"FastMCP:    {checks['fastmcp'].get('version', 'missing')}")
        hive_status = checks["hive_commons"]["status"]
        if hive_status != "not_installed":
            click.echo(f"Hive:       {hive_status}")

        if not API_KEYS_FILE.exists():
            click.echo(
                f"\nNote: No API keys configured. Run: midos-mcp keys generate --tier dev"
            )


# ============================================================================
# VERSION
# ============================================================================


@cli.command()
def version():
    """Show version and environment info."""
    click.echo(f"midos-mcp {__version__}")
    click.echo(f"Python {sys.version.split()[0]}")
    click.echo(f"MIDOS_ROOT={MIDOS_ROOT}")

    try:
        import fastmcp

        click.echo(f"fastmcp {getattr(fastmcp, '__version__', '?')}")
    except ImportError:
        click.echo("fastmcp: not installed")


# ============================================================================
# KEYS (API key management)
# ============================================================================


@cli.group()
def keys():
    """Manage API keys for the MidOS MCP server."""
    pass


@keys.command("generate")
@click.option("--name", required=True, help="Key name/label")
@click.option(
    "--tier",
    type=click.Choice(["dev", "pro", "admin"]),
    default="dev",
    show_default=True,
)
def keys_generate(name, tier):
    """Generate a new API key."""
    import secrets

    key = f"midos_sk_{secrets.token_urlsafe(24)}"
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)

    # Load existing keys
    keys_data = {}
    if API_KEYS_FILE.exists():
        keys_data = json.loads(API_KEYS_FILE.read_text(encoding="utf-8"))

    keys_data[key] = {"name": name, "tier": tier, "active": True}
    API_KEYS_FILE.write_text(json.dumps(keys_data, indent=2), encoding="utf-8")

    click.echo(f"Generated key for '{name}' (tier: {tier}):")
    click.echo(f"  {key}")
    click.echo(f"\nStored in {API_KEYS_FILE}")


@keys.command("list")
def keys_list():
    """List all API keys."""
    if not API_KEYS_FILE.exists():
        click.echo("No API keys configured.")
        return

    keys_data = json.loads(API_KEYS_FILE.read_text(encoding="utf-8"))
    if not keys_data:
        click.echo("No API keys configured.")
        return

    click.echo(f"API Keys ({len(keys_data)}):\n")
    for key, meta in keys_data.items():
        status = "active" if meta.get("active", True) else "revoked"
        # Show only prefix for security
        prefix = key[:16] + "..."
        click.echo(
            f"  {prefix:22s}  {meta.get('name', '?'):15s}  {meta.get('tier', '?'):8s}  {status}"
        )


@keys.command("revoke")
@click.argument("key_prefix")
def keys_revoke(key_prefix):
    """Revoke an API key by its prefix."""
    if not API_KEYS_FILE.exists():
        click.echo("No API keys configured.")
        return

    keys_data = json.loads(API_KEYS_FILE.read_text(encoding="utf-8"))
    matches = [k for k in keys_data if k.startswith(key_prefix)]

    if not matches:
        click.echo(f"No key found matching prefix '{key_prefix}'")
        return

    if len(matches) > 1:
        click.echo(f"Multiple keys match '{key_prefix}'. Be more specific.")
        return

    key = matches[0]
    keys_data[key]["active"] = False
    API_KEYS_FILE.write_text(json.dumps(keys_data, indent=2), encoding="utf-8")
    click.echo(f"Revoked: {key[:16]}...")


if __name__ == "__main__":
    cli()
