"""LSP MCP tool - Code intelligence via Language Server Protocol.

Provides dead code detection, impact analysis, and pre-edit checks.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import Literal


logger = logging.getLogger(__name__)

# Lazy-loaded LSP instance (initialized on first use)
_lsp_instance = None
_workspace_root = None


def _get_lsp(workspace: Path | None = None):
    """Get or create LSP instance (lazy initialization)."""
    global _lsp_instance, _workspace_root

    # Determine workspace
    ws = workspace or Path.cwd()

    # Reinitialize if workspace changed
    if _lsp_instance is None or _workspace_root != ws:
        try:
            from aurora_lsp.facade import AuroraLSP
            _lsp_instance = AuroraLSP(ws)
            _workspace_root = ws
            logger.info(f"Initialized LSP for workspace: {ws}")
        except ImportError:
            logger.error("aurora-lsp package not installed")
            raise ImportError(
                "LSP tools require aurora-lsp package. "
                "Install with: pip install aurora-lsp"
            )

    return _lsp_instance


def _calculate_risk(usage_count: int) -> str:
    """Calculate risk level from usage count.

    Args:
        usage_count: Number of usages

    Returns:
        Risk level: 'low' (0-2), 'medium' (3-10), or 'high' (11+)
    """
    if usage_count <= 2:
        return "low"
    elif usage_count <= 10:
        return "medium"
    else:
        return "high"


def _generate_code_quality_report(dead_code: list[dict], workspace: Path) -> str:
    """Generate CODE_QUALITY_REPORT.md file.

    Args:
        dead_code: List of dead code items
        workspace: Workspace root directory

    Returns:
        Path to generated report
    """
    # Determine report location: docs/ if exists, else root
    docs_dir = workspace / "docs"
    if docs_dir.exists() and docs_dir.is_dir():
        report_path = docs_dir / "CODE_QUALITY_REPORT.md"
    else:
        report_path = workspace / "CODE_QUALITY_REPORT.md"

    # Group by severity
    # For dead code, we'll categorize by kind and usage
    critical = []  # Classes/functions in core files
    high = []      # Public functions/classes
    medium = []    # Protected members
    low = []       # Private members

    for item in dead_code:
        name = item.get("name", "")
        kind = item.get("kind", "")

        # Simple heuristic: private members are low priority
        if name.startswith("_"):
            low.append(item)
        # Classes are higher priority than functions
        elif kind == "class":
            high.append(item)
        elif kind == "function":
            medium.append(item)
        else:
            low.append(item)

    # Generate report content
    lines = [
        "# Code Quality Report",
        "",
        "Generated by Aurora LSP MCP Tool",
        "",
        "## Summary",
        "",
        f"- **Total dead code items:** {len(dead_code)}",
        f"- **Critical:** {len(critical)}",
        f"- **High:** {len(high)}",
        f"- **Medium:** {len(medium)}",
        f"- **Low:** {len(low)}",
        "",
    ]

    # Helper to format section
    def add_section(title: str, items: list[dict]):
        if not items:
            return
        lines.append(f"## {title}")
        lines.append("")
        for item in items:
            file_path = item.get("file", "unknown")
            line_num = item.get("line", 0)
            name = item.get("name", "unknown")
            kind = item.get("kind", "symbol")
            lines.append(f"- `{file_path}:{line_num}` - {kind} **{name}**")
            lines.append("  - Action: Safe to remove (0 usages)")
        lines.append("")

    add_section("Critical Issues", critical)
    add_section("High Priority", high)
    add_section("Medium Priority", medium)
    add_section("Low Priority", low)

    # Write report
    report_path.write_text("\n".join(lines))
    logger.info(f"Generated CODE_QUALITY_REPORT.md at {report_path}")

    return str(report_path)


def lsp(
    action: Literal["deadcode", "impact", "check"] = "check",
    path: str = "",
    line: int | None = None,
) -> dict:
    """Code intelligence - dead code detection, impact analysis, pre-edit usage checks.

    Use this tool BEFORE modifying or deleting functions/classes to understand usage impact.

    Automatic annotation workflow:
    After running deadcode/impact analysis, Claude should automatically add inline markers:
    - After deadcode: Add `#DEADCODE` comments to flagged symbols
    - After high-risk impact: Add `#REFAC` markers

    Supported markers (end-of-line comments):
    - #DEADCODE: 0 usages - safe to remove
    - #REFAC: High usage - careful refactoring needed
    - #UNUSED: Imported but never used
    - #COMPLEX: High complexity
    - #TYPE: Type annotation needed

    Actions:
    - "deadcode": Scan for unused code in a file/directory. Returns list of symbols with 0 usages.
    - "impact": Full impact analysis for a symbol at path:line. Shows all callers and risk level.
    - "check": Quick pre-edit check. Returns usage count and risk level. Use before editing.

    Risk levels:
    - low (0-2 usages): Safe to change
    - medium (3-10 usages): Review callers before changing
    - high (11+ usages): Careful refactoring needed

    Args:
        action: "deadcode" | "impact" | "check" (default: check)
        path: File path (required). For deadcode, can be a directory.
        line: Line number (required for impact/check actions, 1-indexed)

    Returns:
        Action-specific JSON response
    """
    workspace = Path.cwd()
    lsp_client = _get_lsp(workspace)

    if action == "deadcode":
        # Find dead code in path
        target_path = workspace / path if path else None
        dead_code_items = lsp_client.find_dead_code(target_path)

        # Generate CODE_QUALITY_REPORT.md
        report_path = _generate_code_quality_report(dead_code_items, workspace)

        return {
            "action": "deadcode",
            "path": path,
            "dead_code": dead_code_items,
            "total": len(dead_code_items),
            "report_path": report_path,
        }

    elif action == "impact":
        # Full impact analysis
        if line is None:
            raise ValueError("line parameter required for impact action")

        # LSP uses 0-indexed lines, input is 1-indexed
        line_0indexed = line - 1

        # Get usage summary
        summary = lsp_client.get_usage_summary(path, line_0indexed, col=0)

        # Get top callers
        callers = lsp_client.get_callers(path, line_0indexed, col=0)

        # Format top callers with usage counts
        top_callers = []
        usages_by_file = summary.get("usages_by_file", {})
        for caller in callers[:10]:  # Top 10
            caller_file = caller.get("file", "")
            caller_line = caller.get("line", 0)
            caller_name = caller.get("name", "")
            # Count usages from this caller (approximation)
            file_usages = usages_by_file.get(caller_file, [])
            usages_count = len([u for u in file_usages if u.get("name") == caller_name])
            top_callers.append({
                "file": caller_file,
                "line": caller_line + 1,  # Convert back to 1-indexed
                "name": caller_name,
                "usages": usages_count or 1,
            })

        total_usages = summary.get("total_usages", 0)

        return {
            "action": "impact",
            "path": path,
            "line": line,
            "symbol": summary.get("symbol", "unknown"),
            "used_by_files": summary.get("files_affected", 0),
            "total_usages": total_usages,
            "top_callers": top_callers,
            "risk": _calculate_risk(total_usages),
        }

    elif action == "check":
        # Quick pre-edit check
        if line is None:
            raise ValueError("line parameter required for check action")

        # LSP uses 0-indexed lines
        line_0indexed = line - 1

        # Get usage summary (lighter than full impact)
        summary = lsp_client.get_usage_summary(path, line_0indexed, col=0)

        total_usages = summary.get("total_usages", 0)

        return {
            "action": "check",
            "path": path,
            "line": line,
            "symbol": summary.get("symbol", "unknown"),
            "used_by": total_usages,
            "risk": _calculate_risk(total_usages),
        }

    else:
        raise ValueError(f"Unknown action: {action}. Use: deadcode, impact, check")
