"""LangChain tools for code analysis with Tree-sitter and LSP."""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from langchain_core.tools import tool


@tool
def analyze_project(
    path: str = ".",
    extensions: str | None = None,
    max_files: int = 100,
) -> str:
    """Analyze a project directory using Tree-sitter.

    Parses all source files and returns a summary of the codebase structure
    including functions, classes, and imports.

    Args:
        path: Project directory path (default: current directory)
        extensions: Comma-separated file extensions to analyze (e.g., "py,js,ts")
        max_files: Maximum number of files to analyze

    Returns:
        JSON summary of the project structure
    """
    from ieum.analysis.treesitter import TreeSitterParser

    parser = TreeSitterParser()
    project_path = Path(path).resolve()

    ext_list = None
    if extensions:
        ext_list = [e.strip() for e in extensions.split(",")]

    summary = {
        "path": str(project_path),
        "files": [],
        "total_functions": 0,
        "total_classes": 0,
        "languages": {},
    }

    file_count = 0
    for parsed in parser.parse_directory(project_path, ext_list):
        if file_count >= max_files:
            break

        file_info = {
            "path": parsed.file_path,
            "language": parsed.language,
            "functions": [],
            "classes": [],
            "imports": parsed.imports[:20],  # Limit imports
        }

        for node in parsed.nodes:
            if node.type == "function":
                file_info["functions"].append({
                    "name": node.name,
                    "line": node.start_line,
                    "signature": node.signature,
                })
                summary["total_functions"] += 1
            elif node.type == "class":
                file_info["classes"].append({
                    "name": node.name,
                    "line": node.start_line,
                    "signature": node.signature,
                })
                summary["total_classes"] += 1

        summary["files"].append(file_info)
        summary["languages"][parsed.language] = summary["languages"].get(parsed.language, 0) + 1
        file_count += 1

    return json.dumps(summary, indent=2, ensure_ascii=False)


@tool
def build_call_graph(
    path: str,
    focus_function: str | None = None,
    output_format: str = "summary",
) -> str:
    """Build a call graph for a file or directory.

    Analyzes function calls and shows which functions call which.

    Args:
        path: File or directory path to analyze
        focus_function: Optional function name to focus on (shows only related calls)
        output_format: Output format - "summary", "mermaid", or "dot"

    Returns:
        Call graph in the specified format
    """
    from ieum.analysis.treesitter import CallGraphBuilder

    builder = CallGraphBuilder()
    target = Path(path)

    if target.is_file():
        graph = builder.build_from_file(target)
    else:
        graph = builder.build_from_directory(target)

    if output_format == "mermaid":
        return graph.to_mermaid(focus_function)
    elif output_format == "dot":
        return graph.to_dot(focus_function)
    else:
        # Summary format
        result = {
            "total_functions": len(graph.nodes),
            "total_calls": len(graph.edges),
            "entry_points": graph.entry_points[:20],
            "leaf_nodes": graph.leaf_nodes[:20],
        }

        if focus_function:
            result["focus"] = focus_function
            result["callers"] = graph.get_callers(focus_function)
            result["callees"] = graph.get_callees(focus_function)
            result["call_chain"] = graph.get_call_chain(focus_function, max_depth=5)

        return json.dumps(result, indent=2, ensure_ascii=False)


@tool
def analyze_dependencies(
    path: str,
    focus_file: str | None = None,
    output_format: str = "summary",
) -> str:
    """Analyze import/include dependencies in a codebase.

    Shows which files import which modules and detects circular dependencies.

    Args:
        path: File or directory path to analyze
        focus_file: Optional file path to focus on
        output_format: Output format - "summary", "mermaid", or "dot"

    Returns:
        Dependency analysis in the specified format
    """
    from ieum.analysis.treesitter import DependencyAnalyzer

    analyzer = DependencyAnalyzer()
    target = Path(path)

    if target.is_file():
        graph = analyzer.analyze_file(target)
    else:
        graph = analyzer.analyze_directory(target)

    if output_format == "mermaid":
        return graph.to_mermaid(focus_file)
    elif output_format == "dot":
        return graph.to_dot(focus_file)
    else:
        # Summary format
        result = {
            "total_files": len(graph.nodes),
            "total_dependencies": len(graph.edges),
            "external_dependencies": graph.external_deps[:30],
            "circular_dependencies": [list(c) for c in graph.circular_deps],
        }

        if focus_file:
            result["focus"] = focus_file
            result["imports"] = graph.get_imports(focus_file)
            result["imported_by"] = graph.get_importers(focus_file)
            result["dependency_tree"] = graph.get_dependency_tree(focus_file, max_depth=3)

        return json.dumps(result, indent=2, ensure_ascii=False)


@tool
def lsp_get_definition(
    file_path: str,
    line: int,
    character: int,
    workspace: str | None = None,
) -> str:
    """Get the definition location of a symbol using LSP.

    Uses language server to find where a function, class, or variable is defined.

    Args:
        file_path: Path to the file containing the symbol
        line: Line number (0-indexed)
        character: Character position in the line (0-indexed)
        workspace: Optional workspace root path

    Returns:
        JSON with definition location(s)
    """
    from ieum.analysis.lsp import LSPClient

    workspace_path = Path(workspace) if workspace else Path(file_path).parent
    client = LSPClient(workspace_path)

    try:
        locations = client.get_definition(file_path, line, character)

        result = {
            "success": len(locations) > 0,
            "definitions": [
                {
                    "file": loc.file_path,
                    "line": loc.range.start.line + 1,  # 1-indexed for display
                    "character": loc.range.start.character,
                }
                for loc in locations
            ],
        }

        return json.dumps(result, indent=2)
    except Exception as e:
        return json.dumps({"success": False, "error": str(e)})
    finally:
        client.shutdown()


@tool
def lsp_find_references(
    file_path: str,
    line: int,
    character: int,
    include_declaration: bool = True,
    workspace: str | None = None,
) -> str:
    """Find all references to a symbol using LSP.

    Uses language server to find all places where a symbol is used.

    Args:
        file_path: Path to the file containing the symbol
        line: Line number (0-indexed)
        character: Character position in the line (0-indexed)
        include_declaration: Whether to include the declaration itself
        workspace: Optional workspace root path

    Returns:
        JSON with all reference locations
    """
    from ieum.analysis.lsp import LSPClient

    workspace_path = Path(workspace) if workspace else Path(file_path).parent
    client = LSPClient(workspace_path)

    try:
        locations = client.get_references(file_path, line, character, include_declaration)

        result = {
            "success": len(locations) > 0,
            "count": len(locations),
            "references": [
                {
                    "file": loc.file_path,
                    "line": loc.range.start.line + 1,
                    "character": loc.range.start.character,
                }
                for loc in locations
            ],
        }

        return json.dumps(result, indent=2)
    except Exception as e:
        return json.dumps({"success": False, "error": str(e)})
    finally:
        client.shutdown()


@tool
def lsp_get_hover(
    file_path: str,
    line: int,
    character: int,
    workspace: str | None = None,
) -> str:
    """Get hover information for a symbol using LSP.

    Shows type information and documentation for a symbol.

    Args:
        file_path: Path to the file containing the symbol
        line: Line number (0-indexed)
        character: Character position in the line (0-indexed)
        workspace: Optional workspace root path

    Returns:
        JSON with hover information (types, docs)
    """
    from ieum.analysis.lsp import LSPClient

    workspace_path = Path(workspace) if workspace else Path(file_path).parent
    client = LSPClient(workspace_path)

    try:
        hover = client.get_hover(file_path, line, character)

        if hover:
            result = {
                "success": True,
                "contents": hover.contents,
            }
        else:
            result = {"success": False, "error": "No hover information available"}

        return json.dumps(result, indent=2)
    except Exception as e:
        return json.dumps({"success": False, "error": str(e)})
    finally:
        client.shutdown()


@tool
def lsp_get_symbols(
    file_path: str,
    workspace: str | None = None,
) -> str:
    """Get all symbols in a document using LSP.

    Returns all functions, classes, variables defined in a file.

    Args:
        file_path: Path to the file to analyze
        workspace: Optional workspace root path

    Returns:
        JSON with all symbols in the document
    """
    from ieum.analysis.lsp import LSPClient
    from ieum.analysis.lsp.protocol import DocumentSymbol, SymbolInformation

    workspace_path = Path(workspace) if workspace else Path(file_path).parent
    client = LSPClient(workspace_path)

    try:
        symbols = client.get_document_symbols(file_path)

        def symbol_to_dict(sym):
            if isinstance(sym, DocumentSymbol):
                return {
                    "name": sym.name,
                    "kind": sym.kind.name,
                    "line": sym.range.start.line + 1,
                    "detail": sym.detail,
                    "children": [symbol_to_dict(c) for c in sym.children],
                }
            else:  # SymbolInformation
                return {
                    "name": sym.name,
                    "kind": sym.kind.name,
                    "file": sym.location.file_path,
                    "line": sym.location.range.start.line + 1,
                    "container": sym.container_name,
                }

        result = {
            "success": len(symbols) > 0,
            "count": len(symbols),
            "symbols": [symbol_to_dict(s) for s in symbols],
        }

        return json.dumps(result, indent=2)
    except Exception as e:
        return json.dumps({"success": False, "error": str(e)})
    finally:
        client.shutdown()


@tool
def lsp_search_workspace(
    query: str,
    workspace: str = ".",
) -> str:
    """Search for symbols across the workspace using LSP.

    Searches all files in the workspace for matching symbol names.

    Args:
        query: Symbol name or pattern to search for
        workspace: Workspace root path

    Returns:
        JSON with matching symbols
    """
    from ieum.analysis.lsp import LSPClient

    client = LSPClient(workspace)

    try:
        symbols = client.get_workspace_symbols(query)

        result = {
            "success": len(symbols) > 0,
            "count": len(symbols),
            "symbols": [
                {
                    "name": sym.name,
                    "kind": sym.kind.name,
                    "file": sym.location.file_path,
                    "line": sym.location.range.start.line + 1,
                    "container": sym.container_name,
                }
                for sym in symbols
            ],
        }

        return json.dumps(result, indent=2)
    except Exception as e:
        return json.dumps({"success": False, "error": str(e)})
    finally:
        client.shutdown()


@tool
def check_lsp_servers() -> str:
    """Check the status of installed LSP servers.

    Shows which language servers are installed and available.

    Returns:
        JSON with server status for each language
    """
    from ieum.analysis.lsp import LSPServerManager

    manager = LSPServerManager()
    status = manager.get_all_status()

    result = {}
    for lang, st in status.items():
        result[lang.value] = {
            "installed": st.installed,
            "running": st.running,
            "command": st.command,
            "error": st.error,
        }

    return json.dumps(result, indent=2)


# Export all tools
ANALYSIS_TOOLS = [
    analyze_project,
    build_call_graph,
    analyze_dependencies,
    lsp_get_definition,
    lsp_find_references,
    lsp_get_hover,
    lsp_get_symbols,
    lsp_search_workspace,
    check_lsp_servers,
]
