"""Coding toolkit that combines file operations with graph exploration tools."""

from pathlib import Path
from typing import Optional

from emdash.graph.connection import KuzuConnection, get_connection
from emdash.agent.tools.base import BaseTool, ToolResult
from emdash.agent.session import AgentSession
from emdash.utils.logger import log


class CodingToolkit:
    """Toolkit combining coding tools with optional graph exploration tools.

    Provides file operations (read, write, diff, delete, list, execute)
    plus task management, with optional access to semantic code search
    and analysis via the graph database.

    Example:
        toolkit = CodingToolkit(repo_root=Path("."))

        # Read a file
        result = toolkit.execute("read_file", path="src/main.py")

        # Apply a diff
        result = toolkit.execute("apply_diff", path="src/main.py", diff=diff_text)

        # Search code semantically (if graph tools enabled)
        result = toolkit.execute("semantic_search", query="authentication")

        # With planning mode
        toolkit = CodingToolkit(repo_root=Path("."), plan_mode=True)
        # Now includes submit_spec, get_spec, update_spec tools
    """

    def __init__(
        self,
        repo_root: Path,
        connection: Optional[KuzuConnection] = None,
        include_graph_tools: bool = True,
        enable_session: bool = True,
        plan_mode: bool = False,
        save_spec_path: Optional[Path] = None,
    ):
        """Initialize coding toolkit.

        Args:
            repo_root: Root directory of the repository (for path validation)
            connection: Kuzu connection for graph tools. If None, uses global.
            include_graph_tools: Whether to include graph exploration tools
            enable_session: Whether to track exploration state
            plan_mode: Whether to include spec planning tools
            save_spec_path: If provided, specs will be saved to this path
        """
        self.repo_root = repo_root.resolve()
        self.connection = connection or get_connection()
        self.include_graph_tools = include_graph_tools
        self.plan_mode = plan_mode
        self.save_spec_path = save_spec_path
        self.session = AgentSession() if enable_session else None
        self._tools: dict[str, BaseTool] = {}

        # Configure spec state if plan mode
        if plan_mode:
            from emdash.agent.tools.spec import SpecState
            spec_state = SpecState.get_instance()
            spec_state.configure(save_path=save_spec_path)

        self._register_tools()

    def _register_tools(self) -> None:
        """Register all tools."""
        # Register coding tools
        self._register_coding_tools()

        # Register task management tools
        self._register_task_tools()

        # Register web tool (always available)
        self._register_web_tools()

        # Optionally register spec planning tools
        if self.plan_mode:
            self._register_spec_tools()

        # Optionally register graph tools
        if self.include_graph_tools:
            self._register_graph_tools()

        log.debug(f"CodingToolkit registered {len(self._tools)} tools")

    def _register_web_tools(self) -> None:
        """Register web tools (always available)."""
        from emdash.agent.tools.web import WebTool
        self.register_tool(WebTool(self.connection))

    def _register_coding_tools(self) -> None:
        """Register file operation tools."""
        from emdash.agent.tools.coding import (
            ReadFileTool,
            WriteToFileTool,
            ApplyDiffTool,
            DeleteFileTool,
            ListFilesTool,
            ExecuteCommandTool,
        )

        self.register_tool(ReadFileTool(repo_root=self.repo_root))
        self.register_tool(WriteToFileTool(repo_root=self.repo_root))
        self.register_tool(ApplyDiffTool(repo_root=self.repo_root))
        self.register_tool(DeleteFileTool(repo_root=self.repo_root))
        self.register_tool(ListFilesTool(repo_root=self.repo_root))
        self.register_tool(ExecuteCommandTool(repo_root=self.repo_root))

    def _register_task_tools(self) -> None:
        """Register task management tools."""
        from emdash.agent.tools.tasks import (
            NewTaskTool,
            UpdateTodoListTool,
            AskFollowupQuestionTool,
            AttemptCompletionTool,
        )

        self.register_tool(NewTaskTool())
        self.register_tool(UpdateTodoListTool())
        self.register_tool(AskFollowupQuestionTool())
        self.register_tool(AttemptCompletionTool())

    def _register_spec_tools(self) -> None:
        """Register spec planning tools."""
        from emdash.agent.tools.spec import (
            SubmitSpecTool,
            GetSpecTool,
            UpdateSpecTool,
        )

        self.register_tool(SubmitSpecTool())
        self.register_tool(GetSpecTool())
        self.register_tool(UpdateSpecTool())

    def _register_graph_tools(self) -> None:
        """Register graph exploration tools from AgentToolkit."""
        from emdash.agent.tools.search import (
            SemanticSearchTool,
            # TextSearchTool,  # Disabled due to DB locking issues
            GrepTool,
        )
        from emdash.agent.tools.traversal import (
            ExpandNodeTool,
            GetCallersTool,
            GetCalleesTool,
            GetClassHierarchyTool,
            GetFileDependenciesTool,
            GetImpactAnalysisTool,
            GetNeighborsTool,
        )
        from emdash.agent.tools.analytics import (
            GetTopPageRankTool,
            GetCommunitiesTool,
            GetCommunityMembersTool,
        )
        # History tools removed - use GitHub MCP tools instead

        # Search tools
        self.register_tool(SemanticSearchTool(self.connection))
        # self.register_tool(TextSearchTool(self.connection))  # Disabled due to DB locking issues
        self.register_tool(GrepTool(self.connection))

        # Traversal tools
        self.register_tool(ExpandNodeTool(self.connection))
        self.register_tool(GetCallersTool(self.connection))
        self.register_tool(GetCalleesTool(self.connection))
        self.register_tool(GetClassHierarchyTool(self.connection))
        self.register_tool(GetFileDependenciesTool(self.connection))
        self.register_tool(GetImpactAnalysisTool(self.connection))
        self.register_tool(GetNeighborsTool(self.connection))

        # Analytics tools
        self.register_tool(GetTopPageRankTool(self.connection))
        self.register_tool(GetCommunitiesTool(self.connection))
        self.register_tool(GetCommunityMembersTool(self.connection))

        # History/PR tools removed - use GitHub MCP tools instead
        # (github_list_prs, github_pr_details, github_search_prs, etc.)

    def register_tool(self, tool: BaseTool) -> None:
        """Register a tool.

        Args:
            tool: Tool instance to register
        """
        self._tools[tool.name] = tool

    def get_tool(self, name: str) -> Optional[BaseTool]:
        """Get a tool by name.

        Args:
            name: Tool name

        Returns:
            Tool instance or None if not found
        """
        return self._tools.get(name)

    def list_tools(self) -> list[dict]:
        """List all available tools.

        Returns:
            List of tool info dicts
        """
        return [
            {
                "name": tool.name,
                "description": tool.description,
                "category": tool.category.value,
            }
            for tool in self._tools.values()
        ]

    def execute(self, tool_name: str, **params) -> ToolResult:
        """Execute a tool by name.

        Args:
            tool_name: Name of the tool
            **params: Tool parameters

        Returns:
            ToolResult
        """
        tool = self.get_tool(tool_name)

        if not tool:
            return ToolResult.error_result(
                f"Unknown tool: {tool_name}",
                suggestions=[f"Available tools: {list(self._tools.keys())}"],
            )

        try:
            result = tool.execute(**params)

            # Track in session if enabled
            if self.session:
                self.session.record_action(tool_name, params, result)

            return result

        except Exception as e:
            log.exception(f"Tool execution error: {tool_name}")
            return ToolResult.error_result(
                f"Tool execution failed: {str(e)}",
                suggestions=["Check parameters and try again"],
            )

    def get_all_schemas(self) -> list[dict]:
        """Get OpenAI function calling schemas for all tools.

        Returns:
            List of function schemas
        """
        return [tool.get_schema() for tool in self._tools.values()]

    def get_coding_tool_schemas(self) -> list[dict]:
        """Get schemas for coding tools only.

        Returns:
            List of coding tool schemas
        """
        coding_tools = [
            "read_file",
            "write_to_file",
            "apply_diff",
            "delete_file",
            "list_files",
            "execute_command",
        ]
        return [
            tool.get_schema()
            for tool in self._tools.values()
            if tool.name in coding_tools
        ]

    def get_task_tool_schemas(self) -> list[dict]:
        """Get schemas for task management tools.

        Returns:
            List of task tool schemas
        """
        task_tools = [
            "new_task",
            "update_todo_list",
            "ask_followup_question",
            "attempt_completion",
        ]
        return [
            tool.get_schema()
            for tool in self._tools.values()
            if tool.name in task_tools
        ]

    def get_session_context(self) -> Optional[dict]:
        """Get current session context.

        Returns:
            Session context or None
        """
        if self.session:
            return self.session.get_context_summary()
        return None

    def get_exploration_steps(self) -> list:
        """Get exploration steps from the current session.

        Returns:
            List of ExplorationStep objects or empty list
        """
        if self.session:
            return self.session.steps
        return []

    def reset_session(self) -> None:
        """Reset the session state."""
        if self.session:
            self.session.reset()
        # Also reset task state
        from emdash.agent.tools.tasks import TaskState
        TaskState.reset()
        # Also reset spec state if in plan mode
        if self.plan_mode:
            from emdash.agent.tools.spec import SpecState
            SpecState.reset()
