"""
Kodara MCP Server — exposes Kodara as an MCP tool provider.

Tools:
  kodara_ask      — get relevant modules for a question
  kodara_impact   — analyze impact of changing a file
  kodara_context  — get full architecture overview
  kodara_search   — search modules by keyword
  kodara_status   — index status and stats
"""

from __future__ import annotations

import time
from pathlib import Path
from typing import Optional

try:
    import mcp
    HAS_MCP = True
except ImportError:
    HAS_MCP = False


# ── Format helpers (synchronous — testable without MCP) ───────────────────────


def _format_ask_result(index, question: str) -> str:
    """Format context query result as markdown text."""
    from kodara.engine_client import query_context  # type: ignore

    try:
        result = query_context(index.modules, index.graph_edges, question)
    except Exception as exc:
        return f"Error querying index: {exc}"

    lines = [
        f"# Kodara Context",
        f"**Query:** {question}",
        f"**Modules selected:** {len(result['modules'])} / {result['total_modules_searched']}",
        f"**Estimated tokens:** ~{result['token_estimate']:,}",
        "",
    ]

    if result["summaries"]:
        lines.append("## Module Summaries")
        for s in result["summaries"]:
            lines.append(f"- {s}")
        lines.append("")

    lines.append("## Architecture")
    for mod in result["modules"]:
        lines.append(f"\n### `{mod['file']}`")
        lines.append(f"**Module:** `{mod['module']}` · **Language:** {mod['language']}")
        if mod["classes"]:
            lines.append(f"**Classes:** {', '.join(mod['classes'])}")
        if mod["functions"]:
            lines.append(f"**Functions:** {', '.join(mod['functions'][:8])}")
        if mod["dependencies"]:
            lines.append(f"**Internal deps:** {', '.join(mod['dependencies'])}")

    edges = result["graph_fragment"].get("edges", [])
    if edges:
        lines.append("\n## Dependency Flow")
        for edge in edges:
            lines.append(f"- `{edge['from']}` -> `{edge['to']}`")

    return "\n".join(lines)


def _format_impact(index, file_path: str) -> str:
    """Format impact analysis result as markdown text."""
    from kodara.engine_client import query_impact  # type: ignore

    try:
        result = query_impact(index.modules, file_path)
    except ValueError as exc:
        return str(exc)
    except Exception as exc:
        return f"Error analyzing impact: {exc}"

    lines = [
        f"## Impact Analysis: `{result['target_module']}`",
        f"",
        f"**Risk level:** {result['risk_level']}",
        f"**Reason:** {result['risk_reason']}",
        f"**Total affected modules:** {result['total_affected']}",
        f"",
    ]

    if result["target_summary"]:
        lines += [f"**Summary:** {result['target_summary']}", ""]

    if result["direct"]:
        lines.append(f"### Direct impact ({len(result['direct'])} modules)")
        for mod in result["direct"]:
            hub_tag = " [HUB]" if mod["is_hub"] else ""
            lines.append(f"- `{mod['module_name']}`{hub_tag} — {mod['summary'] or mod['path']}")
        lines.append("")

    if result["indirect"]:
        lines.append(f"### Indirect impact ({len(result['indirect'])} modules)")
        for mod in result["indirect"][:10]:
            hub_tag = " [HUB]" if mod["is_hub"] else ""
            lines.append(f"- `{mod['module_name']}`{hub_tag} (distance {mod['distance']})")
        if len(result["indirect"]) > 10:
            lines.append(f"  ... and {len(result['indirect']) - 10} more")
        lines.append("")

    if result["critical_paths"]:
        lines.append("### Critical paths")
        for path in result["critical_paths"]:
            lines.append(f"- {' → '.join(path)}")
        lines.append("")

    return "\n".join(lines)


def _format_context(index) -> str:
    """Render full architecture overview from index (no file write)."""
    from kodara.injector.inject import _render  # type: ignore

    try:
        return _render(index)
    except Exception as exc:
        return f"Error generating context: {exc}"


def _format_search(index, query: str) -> str:
    """Score all modules against query and return top-10 list."""
    from kodara.engine_client import query_context  # type: ignore

    try:
        result = query_context(index.modules, index.graph_edges, query, max_modules=10)
    except Exception as exc:
        return f"Search error: {exc}"

    if not result["modules"]:
        return f"No modules matched query: {query}"

    lines = [f"## Search results for: `{query}`", ""]
    for rank, mod in enumerate(result["modules"], 1):
        name = mod.get("module", mod.get("file", ""))
        path = mod.get("file", "")
        summary = mod.get("summary", "")
        summary_str = f" — {summary}" if summary else ""
        lines.append(f"{rank}. **{name}** (`{path}`){summary_str}")

    return "\n".join(lines)


def _format_status(index) -> str:
    """Return index metadata as human-readable text."""
    from datetime import datetime  # noqa: PLC0415

    indexed_dt = datetime.fromtimestamp(index.indexed_at).strftime("%Y-%m-%d %H:%M")
    langs = ", ".join(f"{lang} ({count})" for lang, count in index.language_counts.items())

    # Find hub modules (most-imported)
    import_counts: dict[str, int] = {}
    for mod in index.modules.values():
        for dep in mod.get("dependencies", []):
            import_counts[dep] = import_counts.get(dep, 0) + 1

    top_hubs = sorted(import_counts.items(), key=lambda x: -x[1])[:5]

    lines = [
        "## Kodara Index Status",
        "",
        f"**Project:** {index.display_name}",
        f"**Indexed at:** {indexed_dt}",
        f"**Files:** {index.file_count}",
        f"**Modules:** {len(index.modules)}",
        f"**Languages:** {langs}",
        f"**Graph edges:** {len(index.graph_edges)}",
        "",
    ]

    if top_hubs:
        lines.append("**Hub modules (most imported):**")
        for path, count in top_hubs:
            name = index.modules.get(path, {}).get("module_name", Path(path).stem)
            lines.append(f"- `{name}` — {count} dependents")
        lines.append("")

    return "\n".join(lines)


# ── Not-indexed sentinel ───────────────────────────────────────────────────────

_NOT_INDEXED = "Project not indexed. Run: kodara init"


# ── MCP Server ────────────────────────────────────────────────────────────────


async def run_server(project_root: str) -> None:
    """Start Kodara MCP server for the given project root."""
    if not HAS_MCP:
        raise ImportError(
            "MCP package is not installed. Install with: pip install kodara[pro]"
        )

    from mcp.server import Server  # type: ignore
    from mcp.server.models import InitializationOptions  # type: ignore
    class _NotifOpts:
        tools_changed = False
    _NOTIFICATION_OPTIONS = _NotifOpts()
    import mcp.server.stdio  # type: ignore
    import mcp.types as types  # type: ignore

    from kodara.memory.store import MemoryStore  # type: ignore

    # Load index once at startup
    store = MemoryStore(project_root)
    index = store.load()  # may be None if not yet indexed

    server = Server("kodara")

    @server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        return [
            types.Tool(
                name="kodara_ask",
                description="Get relevant code modules for a question about the codebase",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "question": {
                            "type": "string",
                            "description": "Question about the codebase",
                        }
                    },
                    "required": ["question"],
                },
            ),
            types.Tool(
                name="kodara_impact",
                description="Analyze the blast radius of changing a file",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "file": {
                            "type": "string",
                            "description": "File path to analyze",
                        }
                    },
                    "required": ["file"],
                },
            ),
            types.Tool(
                name="kodara_context",
                description="Get the full architecture overview of the project",
                inputSchema={
                    "type": "object",
                    "properties": {},
                },
            ),
            types.Tool(
                name="kodara_search",
                description="Search modules by keyword",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {
                            "type": "string",
                            "description": "Search query",
                        }
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="kodara_status",
                description="Show index status and project stats",
                inputSchema={
                    "type": "object",
                    "properties": {},
                },
            ),
        ]

    @server.call_tool()
    async def handle_call_tool(
        name: str, arguments: dict | None
    ) -> list[types.TextContent]:
        args = arguments or {}

        if index is None:
            return [types.TextContent(type="text", text=_NOT_INDEXED)]

        if name == "kodara_ask":
            question = args.get("question", "")
            text = _format_ask_result(index, question)
            return [types.TextContent(type="text", text=text)]

        if name == "kodara_impact":
            file_path = args.get("file", "")
            text = _format_impact(index, file_path)
            return [types.TextContent(type="text", text=text)]

        if name == "kodara_context":
            text = _format_context(index)
            return [types.TextContent(type="text", text=text)]

        if name == "kodara_search":
            query = args.get("query", "")
            text = _format_search(index, query)
            return [types.TextContent(type="text", text=text)]

        if name == "kodara_status":
            text = _format_status(index)
            return [types.TextContent(type="text", text=text)]

        return [types.TextContent(type="text", text=f"Unknown tool: {name}")]

    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="kodara",
                server_version="0.2.4",
                capabilities=server.get_capabilities(
                    notification_options=_NOTIFICATION_OPTIONS,
                    experimental_capabilities={},
                ),
            ),
        )
