"""LSP-based code navigation tools using cclsp MCP server.

These tools provide IDE-level code intelligence using the Language Server Protocol
via the cclsp MCP server. They offer real-time, accurate code navigation without
requiring pre-indexing.

Enable with USE_LSP=true (disabled by default).
"""

import os
from typing import Optional

from .base import BaseTool, ToolResult, ToolCategory
from ...utils.logger import log


def is_lsp_enabled() -> bool:
    """Check if LSP tools should be used.

    Returns:
        True if USE_LSP is explicitly set to 'true' (disabled by default)
    """
    return os.getenv("USE_LSP", "false").lower() == "true"


class LSPFindDefinitionTool(BaseTool):
    """Find the definition of a symbol using LSP."""

    name = "find_definition"
    description = """Find where a symbol (function, class, variable) is defined.
Uses Language Server Protocol for accurate, real-time results.
Returns the file path and location of the definition."""
    category = ToolCategory.TRAVERSAL

    def __init__(self, mcp_manager, connection=None):
        """Initialize the LSP tool.

        Args:
            mcp_manager: MCP server manager for calling cclsp
            connection: Optional Kuzu connection (for compatibility)
        """
        super().__init__(connection)
        self._mcp_manager = mcp_manager

    def execute(
        self,
        file_path: str,
        symbol_name: str,
        symbol_kind: str = "function",
    ) -> ToolResult:
        """Find the definition of a symbol.

        Args:
            file_path: Path to the file containing the symbol reference
            symbol_name: Name of the symbol to find definition for
            symbol_kind: Kind of symbol (function, class, variable, method)

        Returns:
            ToolResult with definition location
        """
        try:
            response = self._mcp_manager.call_tool("find_definition", {
                "file": file_path,
                "name": symbol_name,
                "kind": symbol_kind,
            })

            if not response.content:
                return ToolResult.error_result(
                    f"No definition found for '{symbol_name}'",
                    suggestions=["Check the symbol name spelling", "Try a different symbol_kind"],
                )

            # Parse response content
            content = response.content[0] if response.content else {}
            text = content.get("text", "") if isinstance(content, dict) else str(content)

            return ToolResult.success_result(
                data={
                    "symbol": symbol_name,
                    "kind": symbol_kind,
                    "definition": text,
                },
            )

        except Exception as e:
            log.exception("LSP find_definition failed")
            return ToolResult.error_result(f"Failed to find definition: {str(e)}")

    def get_schema(self) -> dict:
        """Get OpenAI function schema."""
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to the file containing the symbol reference",
                },
                "symbol_name": {
                    "type": "string",
                    "description": "Name of the symbol to find definition for",
                },
                "symbol_kind": {
                    "type": "string",
                    "enum": ["function", "class", "variable", "method", "interface", "type"],
                    "description": "Kind of symbol",
                    "default": "function",
                },
            },
            required=["file_path", "symbol_name"],
        )


class LSPFindReferencesTool(BaseTool):
    """Find all references to a symbol using LSP."""

    name = "find_references"
    description = """Find all usages/references of a symbol across the codebase.
Uses Language Server Protocol for accurate, real-time results.
Similar to 'Find All References' in an IDE."""
    category = ToolCategory.TRAVERSAL

    def __init__(self, mcp_manager, connection=None):
        """Initialize the LSP tool.

        Args:
            mcp_manager: MCP server manager for calling cclsp
            connection: Optional Kuzu connection (for compatibility)
        """
        super().__init__(connection)
        self._mcp_manager = mcp_manager

    def execute(
        self,
        file_path: str,
        symbol_name: str,
        symbol_kind: str = "function",
        include_declaration: bool = True,
    ) -> ToolResult:
        """Find all references to a symbol.

        Args:
            file_path: Path to the file containing the symbol
            symbol_name: Name of the symbol to find references for
            symbol_kind: Kind of symbol (function, class, variable, method)
            include_declaration: Whether to include the declaration itself

        Returns:
            ToolResult with list of references
        """
        try:
            response = self._mcp_manager.call_tool("find_references", {
                "file": file_path,
                "name": symbol_name,
                "kind": symbol_kind,
                "includeDeclaration": include_declaration,
            })

            if not response.content:
                return ToolResult.error_result(
                    f"No references found for '{symbol_name}'",
                    suggestions=["Check the symbol name spelling", "The symbol may not be used anywhere"],
                )

            content = response.content[0] if response.content else {}
            text = content.get("text", "") if isinstance(content, dict) else str(content)

            return ToolResult.success_result(
                data={
                    "symbol": symbol_name,
                    "kind": symbol_kind,
                    "references": text,
                },
            )

        except Exception as e:
            log.exception("LSP find_references failed")
            return ToolResult.error_result(f"Failed to find references: {str(e)}")

    def get_schema(self) -> dict:
        """Get OpenAI function schema."""
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to the file containing the symbol",
                },
                "symbol_name": {
                    "type": "string",
                    "description": "Name of the symbol to find references for",
                },
                "symbol_kind": {
                    "type": "string",
                    "enum": ["function", "class", "variable", "method", "interface", "type"],
                    "description": "Kind of symbol",
                    "default": "function",
                },
                "include_declaration": {
                    "type": "boolean",
                    "description": "Whether to include the declaration in results",
                    "default": True,
                },
            },
            required=["file_path", "symbol_name"],
        )


class LSPRenameSymbolTool(BaseTool):
    """Rename a symbol across the codebase using LSP."""

    name = "rename_symbol"
    description = """Safely rename a symbol (function, class, variable) across all files.
Uses Language Server Protocol for semantic renaming that understands code structure.
Much safer than find-and-replace."""
    category = ToolCategory.TRAVERSAL

    def __init__(self, mcp_manager, connection=None):
        """Initialize the LSP tool.

        Args:
            mcp_manager: MCP server manager for calling cclsp
            connection: Optional Kuzu connection (for compatibility)
        """
        super().__init__(connection)
        self._mcp_manager = mcp_manager

    def execute(
        self,
        file_path: str,
        old_name: str,
        new_name: str,
        symbol_kind: str = "function",
    ) -> ToolResult:
        """Rename a symbol across the codebase.

        Args:
            file_path: Path to the file containing the symbol
            old_name: Current name of the symbol
            new_name: New name for the symbol
            symbol_kind: Kind of symbol (function, class, variable, method)

        Returns:
            ToolResult with rename results
        """
        try:
            response = self._mcp_manager.call_tool("rename_symbol", {
                "file": file_path,
                "name": old_name,
                "newName": new_name,
                "kind": symbol_kind,
            })

            if not response.content:
                return ToolResult.error_result(
                    f"Failed to rename '{old_name}' to '{new_name}'",
                    suggestions=["Check the symbol name", "Try rename_symbol_strict for precise matching"],
                )

            content = response.content[0] if response.content else {}
            text = content.get("text", "") if isinstance(content, dict) else str(content)

            return ToolResult.success_result(
                data={
                    "old_name": old_name,
                    "new_name": new_name,
                    "kind": symbol_kind,
                    "result": text,
                },
            )

        except Exception as e:
            log.exception("LSP rename_symbol failed")
            return ToolResult.error_result(f"Failed to rename symbol: {str(e)}")

    def get_schema(self) -> dict:
        """Get OpenAI function schema."""
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to the file containing the symbol",
                },
                "old_name": {
                    "type": "string",
                    "description": "Current name of the symbol",
                },
                "new_name": {
                    "type": "string",
                    "description": "New name for the symbol",
                },
                "symbol_kind": {
                    "type": "string",
                    "enum": ["function", "class", "variable", "method", "interface", "type"],
                    "description": "Kind of symbol",
                    "default": "function",
                },
            },
            required=["file_path", "old_name", "new_name"],
        )


class LSPGetDiagnosticsTool(BaseTool):
    """Get diagnostics (errors, warnings) for a file using LSP."""

    name = "get_diagnostics"
    description = """Get errors, warnings, and other diagnostics for a file.
Uses Language Server Protocol to provide real-time feedback without running the compiler.
Useful for checking code health before making changes."""
    category = ToolCategory.ANALYTICS

    def __init__(self, mcp_manager, connection=None):
        """Initialize the LSP tool.

        Args:
            mcp_manager: MCP server manager for calling cclsp
            connection: Optional Kuzu connection (for compatibility)
        """
        super().__init__(connection)
        self._mcp_manager = mcp_manager

    def execute(
        self,
        file_path: str,
    ) -> ToolResult:
        """Get diagnostics for a file.

        Args:
            file_path: Path to the file to check

        Returns:
            ToolResult with diagnostics
        """
        try:
            response = self._mcp_manager.call_tool("get_diagnostics", {
                "file": file_path,
            })

            content = response.content[0] if response.content else {}
            text = content.get("text", "") if isinstance(content, dict) else str(content)

            return ToolResult.success_result(
                data={
                    "file": file_path,
                    "diagnostics": text,
                },
            )

        except Exception as e:
            log.exception("LSP get_diagnostics failed")
            return ToolResult.error_result(f"Failed to get diagnostics: {str(e)}")

    def get_schema(self) -> dict:
        """Get OpenAI function schema."""
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to the file to check for diagnostics",
                },
            },
            required=["file_path"],
        )
