"""DebtMap MCP Server — Expose debt analysis tools via Model Context Protocol.

Run with: python -m debtmap.server
Or configure in Claude Desktop / MCP client.
"""

from __future__ import annotations

import json
import sys
from pathlib import Path
from typing import Any

try:
    from mcp.server import Server
    from mcp.server.stdio import run_server
    from mcp.types import Tool, TextContent

    HAS_MCP = True
except ImportError:
    HAS_MCP = False

from .core.scanner import Scanner
from .core.prioritizer import Prioritizer
from .core.trend_analyzer import TrendAnalyzer
from .core.report_generator import ReportGenerator
from .business.cost_estimator import CostEstimator
from .store import DebtStore


def _create_tools() -> list[dict[str, Any]]:
    """Define all MCP tools."""
    return [
        {
            "name": "debt_scan",
            "description": (
                "Scan a codebase for technical debt. Analyzes complexity, coupling, "
                "duplication, dead code, test coverage gaps, documentation gaps, "
                "and dependency freshness. Returns a comprehensive debt score."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory to scan",
                    },
                    "exclude": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "Directory names to exclude from scanning",
                    },
                    "skip_dependency_check": {
                        "type": "boolean",
                        "description": "Skip PyPI version checks for faster scanning",
                        "default": False,
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_hotspots",
            "description": (
                "Find the worst code hotspots — functions with the highest "
                "cyclomatic complexity. These are the most maintenance-prone "
                "areas of the codebase."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                    "threshold": {
                        "type": "integer",
                        "description": "Minimum complexity to report (default: 10)",
                        "default": 10,
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Max hotspots to return (default: 20)",
                        "default": 20,
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_prioritize",
            "description": (
                "Get an ROI-ranked list of what to fix first. Each item shows "
                "the fix effort, estimated savings, and payback period."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                    "limit": {
                        "type": "integer",
                        "description": "Max items to return (default: 20)",
                        "default": 20,
                    },
                    "hourly_rate": {
                        "type": "number",
                        "description": "Engineer hourly rate in USD (default: 75)",
                        "default": 75,
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_cost",
            "description": (
                "Estimate the dollar cost of technical debt. Shows monthly and "
                "annual costs, fix effort, and team capacity waste percentage."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                    "hourly_rate": {
                        "type": "number",
                        "description": "Engineer hourly rate in USD (default: 75)",
                        "default": 75,
                    },
                    "team_size": {
                        "type": "integer",
                        "description": "Number of engineers (default: 5)",
                        "default": 5,
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_trend",
            "description": (
                "Show the debt trend over time. Compares historical scans to "
                "determine if debt is improving, stable, or degrading."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_report",
            "description": (
                "Generate an executive-ready debt report with analysis breakdown, "
                "trends, and prioritized action items."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                    "format": {
                        "type": "string",
                        "enum": ["text", "json"],
                        "description": "Report format (default: text)",
                        "default": "text",
                    },
                },
                "required": ["path"],
            },
        },
        {
            "name": "debt_compare",
            "description": (
                "Compare debt levels between two branches or releases. "
                "Shows which branch has better code quality."
            ),
            "inputSchema": {
                "type": "object",
                "properties": {
                    "path": {
                        "type": "string",
                        "description": "Path to the codebase directory",
                    },
                    "branch_a": {
                        "type": "string",
                        "description": "First branch name",
                    },
                    "branch_b": {
                        "type": "string",
                        "description": "Second branch name",
                    },
                },
                "required": ["path", "branch_a", "branch_b"],
            },
        },
    ]


def _handle_tool(name: str, arguments: dict[str, Any]) -> str:
    """Execute a tool and return the result as a string."""
    store = DebtStore()
    scanner = Scanner(store=store)

    if name == "debt_scan":
        result = scanner.scan(
            directory=arguments["path"],
            exclude_patterns=arguments.get("exclude"),
            skip_dependency_check=arguments.get("skip_dependency_check", False),
        )
        return json.dumps(result, indent=2, default=str)

    elif name == "debt_hotspots":
        from .analyzers.complexity import ComplexityAnalyzer

        analyzer = ComplexityAnalyzer()
        results = analyzer.analyze_directory(arguments["path"])
        hotspots = analyzer.get_hotspots(
            results,
            threshold=arguments.get("threshold", 10),
            limit=arguments.get("limit", 20),
        )
        return json.dumps(
            {"hotspots": [h.to_dict() for h in hotspots], "summary": analyzer.summary(results)},
            indent=2,
        )

    elif name == "debt_prioritize":
        prioritizer = Prioritizer(
            hourly_rate_usd=arguments.get("hourly_rate", 75),
        )
        scan_result = scanner.scan(
            directory=arguments["path"], skip_dependency_check=True
        )
        items = prioritizer.prioritize(scan_result, limit=arguments.get("limit", 20))
        return json.dumps(
            {
                "items": [i.to_dict() for i in items],
                "summary": prioritizer.summary(items),
            },
            indent=2,
        )

    elif name == "debt_cost":
        estimator = CostEstimator(
            hourly_rate_usd=arguments.get("hourly_rate", 75),
            team_size=arguments.get("team_size", 5),
        )
        scan_result = scanner.scan(
            directory=arguments["path"], skip_dependency_check=True
        )
        details = scan_result.get("details", {})
        file_complexity: dict[str, float] = {}
        for h in details.get("complexity_hotspots", []):
            fp = h["file_path"]
            file_complexity[fp] = max(file_complexity.get(fp, 0), h["complexity"])

        estimates = [
            estimator.estimate_file(file_path=fp, complexity_score=cx)
            for fp, cx in file_complexity.items()
        ]
        project = estimator.estimate_project(estimates)
        return json.dumps(project, indent=2)

    elif name == "debt_trend":
        trend_analyzer = TrendAnalyzer(store=store)
        repo_path = str(Path(arguments["path"]).resolve())
        result = trend_analyzer.analyze(repo_path)
        return json.dumps(result.to_dict(), indent=2)

    elif name == "debt_report":
        prioritizer = Prioritizer()
        trend_analyzer = TrendAnalyzer(store=store)
        reporter = ReportGenerator()

        scan_result = scanner.scan(
            directory=arguments["path"], skip_dependency_check=True
        )
        items = prioritizer.prioritize(scan_result)
        repo_path = str(Path(arguments["path"]).resolve())
        trend = trend_analyzer.analyze(repo_path)

        fmt = arguments.get("format", "text")
        if fmt == "json":
            return reporter.generate_json_report(
                scan_result,
                [i.to_dict() for i in items],
                trend.to_dict(),
            )
        return reporter.generate_executive_summary(
            scan_result,
            [i.to_dict() for i in items],
            trend.to_dict(),
        )

    elif name == "debt_compare":
        trend_analyzer = TrendAnalyzer(store=store)
        repo_path = str(Path(arguments["path"]).resolve())
        result = trend_analyzer.compare_branches(
            repo_path, arguments["branch_a"], arguments["branch_b"]
        )
        return json.dumps(result, indent=2)

    return json.dumps({"error": f"Unknown tool: {name}"})


def create_server() -> Any:
    """Create and configure the MCP server."""
    if not HAS_MCP:
        raise ImportError(
            "MCP SDK not installed. Install with: pip install 'autoai-debtmap[mcp]'"
        )

    server = Server("debtmap")

    @server.list_tools()
    async def list_tools() -> list[Tool]:
        tools_data = _create_tools()
        return [
            Tool(
                name=t["name"],
                description=t["description"],
                inputSchema=t["inputSchema"],
            )
            for t in tools_data
        ]

    @server.call_tool()
    async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
        result = _handle_tool(name, arguments)
        return [TextContent(type="text", text=result)]

    return server


async def _run() -> None:
    """Run the MCP server."""
    server = create_server()
    await run_server(server)


def main() -> None:
    """Entry point for MCP server."""
    import asyncio

    if not HAS_MCP:
        print("MCP SDK not installed. Install with: pip install 'autoai-debtmap[mcp]'")
        print("Falling back to CLI mode. Use 'debtmap' command instead.")
        sys.exit(1)

    asyncio.run(_run())


if __name__ == "__main__":
    main()
