"""Toolkit for the Open Agent.

Extends the CoworkerToolkit with self-modification tools that allow
the agent to learn, evolve, and manage its own capabilities.

Includes hierarchical memory tools for:
- Core Identity: Fundamental user traits
- Long-term Memory: Learned preferences and patterns
- Short-term Memory: Session context
- Skill Memory: Dynamic skills and rules
"""

from typing import Optional
from pathlib import Path

from ..toolkits.base import BaseToolkit
from ..tools.base import BaseTool, ToolResult
from .persona import PersonaManager
from .capabilities import CapabilityRegistry
from .tools import (
    LearnPreferenceTool,
    AddCapabilityTool,
    RemoveCapabilityTool,
    ListCapabilitiesTool,
    ExportPersonaTool,
    ImportPersonaTool,
    SuggestSkillTool,
)
from .memory import HierarchicalMemory
from .memory_tools import MemoryToolSet
from .skill_memory import SkillMemoryManager


class OpenToolkit(BaseToolkit):
    """Toolkit for Open Agent with hierarchical memory and self-modification.

    Inherits base tools from the toolkit system and adds:
    - Learning tools (persona/capabilities)
    - Memory tools (hierarchical memory system)
    - Skill tools (dynamic skill management)
    """

    TOOLS = [
        # Learning/self-modification tools (legacy)
        "learn_preference",
        "add_capability",
        "remove_capability",
        "list_capabilities",
        "export_persona",
        "import_persona",
        "suggest_skill",
        # Hierarchical memory tools
        "remember",
        "recall",
        "forget",
        "show_identity",
        "set_identity",
        "list_memories",
        "suggest_consolidation",
        "export_memory",
        "show_memory_stats",
        "reset_memory",
        # Skill management tools
        "add_rule",
        "learn_skill",
        "list_rules",
        "list_skills",
        "get_skill_suggestions",
        # Channel management
        "manage_channel",
        # MCP server management
        "manage_mcp",
        # Automation (cron, heartbeat, webhooks)
        "manage_automation",
        # Inherited from base:
        "read_file",
        "list_files",
        "glob",
        "grep",
        "semantic_search",
        "web_search",
        "execute_command",
        "task",
        "write_todo",
        "update_todo_list",
        "complete_todo",
        "get_claimable_todos",
        "skill",
        "list_skills",
    ]

    def __init__(
        self,
        repo_root: Path,
        persona_manager: Optional[PersonaManager] = None,
        capability_registry: Optional[CapabilityRegistry] = None,
        hierarchical_memory: Optional[HierarchicalMemory] = None,
        skill_memory_manager: Optional[SkillMemoryManager] = None,
        memory_tools: Optional[MemoryToolSet] = None,
        **kwargs,
    ):
        """Initialize the Open Toolkit.

        Args:
            repo_root: Root directory of the repository
            persona_manager: Optional pre-configured PersonaManager
            capability_registry: Optional pre-configured CapabilityRegistry
            hierarchical_memory: Optional pre-configured HierarchicalMemory
            skill_memory_manager: Optional pre-configured SkillMemoryManager
            memory_tools: Optional pre-configured MemoryToolSet
            **kwargs: Additional arguments passed to BaseToolkit
        """
        # Initialize all fields BEFORE super().__init__() because it calls _register_tools()

        # Initialize or use provided persona manager
        if persona_manager:
            self._persona = persona_manager
        else:
            self._persona = PersonaManager(
                user_id="default",
                emdash_dir=repo_root / ".emdash",
            )

        # Initialize or use provided capability registry
        if capability_registry:
            self._capabilities = capability_registry
        else:
            self._capabilities = CapabilityRegistry(
                emdash_dir=repo_root / ".emdash",
            )

        # Initialize or use provided hierarchical memory
        if hierarchical_memory:
            self._memory = hierarchical_memory
        elif memory_tools:
            self._memory = memory_tools.memory
        else:
            self._memory = HierarchicalMemory(
                session_id="default",
                emdash_dir=repo_root / ".emdash",
            )

        # Initialize memory tools wrapper
        if memory_tools:
            self._memory_tools = memory_tools
        else:
            self._memory_tools = MemoryToolSet(self._memory)

        # Initialize skill memory manager
        if skill_memory_manager:
            self._skill_memory = skill_memory_manager
        else:
            self._skill_memory = SkillMemoryManager(
                storage_dir=repo_root / ".emdash" / "memory" / "skills",
            )

        super().__init__(repo_root=repo_root, **kwargs)

    def _register_tools(self) -> None:
        """Register all tools for the Open Agent."""
        # Import base tools
        from ..tools.coding import ReadFileTool, ListFilesTool, ExecuteCommandTool
        from ..tools.search import GlobTool, GrepTool, SemanticSearchTool
        from ..tools.web import WebTool
        from ..tools.task import TaskTool
        from ..tools.tasks import (
            WriteTodoTool,
            UpdateTodoListTool,
            CompleteTodoTool,
            GetClaimableTodosTool,
        )
        from ..tools.skill import SkillTool, ListSkillsTool

        # Register base tools
        self._tools["read_file"] = ReadFileTool(repo_root=self.repo_root)
        self._tools["list_files"] = ListFilesTool(repo_root=self.repo_root)
        self._tools["glob"] = GlobTool()
        self._tools["grep"] = GrepTool()
        self._tools["semantic_search"] = SemanticSearchTool()
        self._tools["web_search"] = WebTool()
        self._tools["execute_command"] = ExecuteCommandTool(repo_root=self.repo_root)
        self._tools["task"] = TaskTool(repo_root=self.repo_root)
        self._tools["write_todo"] = WriteTodoTool()
        self._tools["update_todo_list"] = UpdateTodoListTool()
        self._tools["complete_todo"] = CompleteTodoTool()
        self._tools["get_claimable_todos"] = GetClaimableTodosTool()
        self._tools["skill"] = SkillTool()
        self._tools["list_skills"] = ListSkillsTool()

        # Load skills from registry (built-in, global, repo-local)
        # This must happen so SkillTool can find skills like /telegram
        from ..skills import SkillRegistry
        registry = SkillRegistry.get_instance()
        registry.load_skills()

        # Register channel management tool
        from ..tools.channel import ChannelTool
        self._tools["manage_channel"] = ChannelTool()

        # Register MCP management tool (pass self so it can hot-load tools)
        from ..tools.mcp import MCPTool
        self._tools["manage_mcp"] = MCPTool(toolkit=self)

        # Register automation tool (cron, heartbeat, webhooks)
        from ..tools.automation import AutomationTool
        self._tools["manage_automation"] = AutomationTool()

        # Register legacy self-modification tools
        self._tools["learn_preference"] = LearnPreferenceTool(self._persona)
        self._tools["add_capability"] = AddCapabilityTool(self._capabilities)
        self._tools["remove_capability"] = RemoveCapabilityTool(self._capabilities)
        self._tools["list_capabilities"] = ListCapabilitiesTool(self._capabilities)
        self._tools["export_persona"] = ExportPersonaTool(self._persona, self._capabilities)
        self._tools["import_persona"] = ImportPersonaTool(self._persona, self._capabilities)
        self._tools["suggest_skill"] = SuggestSkillTool(self._persona, self._capabilities)

        # Register hierarchical memory tools
        self._register_memory_tools()

        # Register skill memory tools
        self._register_skill_tools()

    def _register_memory_tools(self) -> None:
        """Register hierarchical memory tools as callable tools."""
        memory_tools = self._memory_tools

        class RememberTool(BaseTool):
            name = "remember"
            description = "Store information in memory (core/long_term/short_term)"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"content": {"type": "string", "description": "The information to remember"}, "layer": {"type": "string", "description": "Which layer (core/long_term/short_term)"}, "importance": {"type": "number", "description": "Importance 0.0-1.0"}, "context": {"type": "string", "description": "Category"}, "tags": {"type": "array", "items": {"type": "string"}, "description": "List of tags"}}, required=["content"])
            def execute(self, content: str, layer: str = "long_term", importance: float = 0.5, context: str = "general", tags: list = None, **kwargs):
                result = self._mt.remember(content, layer, None, importance, context, tags or [])
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class RecallTool(BaseTool):
            name = "recall"
            description = "Search memory for stored information"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"query": {"type": "string", "description": "Search query"}, "layers": {"type": "array", "items": {"type": "string"}, "description": "Which layers to search"}, "context": {"type": "string", "description": "Filter by context"}, "top_k": {"type": "integer", "description": "Max results"}}, required=["query"])
            def execute(self, query: str, layers: list = None, context: str = None, top_k: int = 5, **kwargs):
                result = self._mt.recall(query, layers, context, top_k)
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class ShowIdentityTool(BaseTool):
            name = "show_identity"
            description = "Show the user's core identity (fundamental traits)"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({})
            def execute(self, **kwargs):
                result = self._mt.show_identity()
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class SetIdentityTool(BaseTool):
            name = "set_identity"
            description = "Set a fundamental user trait (role, values, goals)"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"key": {"type": "string", "description": "Identity aspect (e.g., 'role', 'values')"}, "value": {"type": "string", "description": "The identity information"}, "importance": {"type": "number", "description": "How fundamental (0.0-1.0)"}}, required=["key", "value"])
            def execute(self, key: str, value: str, importance: float = 1.0, **kwargs):
                result = self._mt.set_identity(key, value, importance)
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class ListMemoriesTool(BaseTool):
            name = "list_memories"
            description = "List stored memories"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"layer": {"type": "string", "description": "Which layer (core/long_term/short_term)"}, "context": {"type": "string", "description": "Filter by context"}, "limit": {"type": "integer", "description": "Max results"}})
            def execute(self, layer: str = "long_term", context: str = None, limit: int = 20, **kwargs):
                result = self._mt.list_memories(layer, context, limit)
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class SuggestConsolidationTool(BaseTool):
            name = "suggest_consolidation"
            description = "Analyze short-term memory and suggest what to remember long-term"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({})
            def execute(self, **kwargs):
                result = self._mt.suggest_consolidation()
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class ExportMemoryTool(BaseTool):
            name = "export_memory"
            description = "Export all memory layers"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"layer": {"type": "string", "description": "Specific layer or all"}})
            def execute(self, layer: str = None, **kwargs):
                result = self._mt.export_memory(layer)
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class ShowMemoryStatsTool(BaseTool):
            name = "show_memory_stats"
            description = "Show memory usage statistics"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({})
            def execute(self, **kwargs):
                result = self._mt.get_memory_stats()
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        class ResetMemoryTool(BaseTool):
            name = "reset_memory"
            description = "Reset memory layer(s) - use with caution"
            def __init__(self, mt): super().__init__(); self._mt = mt
            def get_schema(self):
                return self._make_schema({"layer": {"type": "string", "description": "Which layer or 'all'"}, "confirm": {"type": "boolean", "description": "Must be True to proceed"}})
            def execute(self, layer: str = None, confirm: bool = False, **kwargs):
                result = self._mt.reset_memory(layer, confirm)
                return ToolResult.success_result(data=result) if result.get("success") else ToolResult.error_result(result.get("error", "Unknown error"))

        self._tools["remember"] = RememberTool(memory_tools)
        self._tools["recall"] = RecallTool(memory_tools)
        self._tools["show_identity"] = ShowIdentityTool(memory_tools)
        self._tools["set_identity"] = SetIdentityTool(memory_tools)
        self._tools["list_memories"] = ListMemoriesTool(memory_tools)
        self._tools["suggest_consolidation"] = SuggestConsolidationTool(memory_tools)
        self._tools["export_memory"] = ExportMemoryTool(memory_tools)
        self._tools["show_memory_stats"] = ShowMemoryStatsTool(memory_tools)
        self._tools["reset_memory"] = ResetMemoryTool(memory_tools)

    def _register_skill_tools(self) -> None:
        """Register skill memory management tools."""
        skill_memory = self._skill_memory

        class AddRuleTool(BaseTool):
            name = "add_rule"
            description = "Add a new behavior rule that triggers automatically"
            def __init__(self, sm): super().__init__(); self._sm = sm
            def get_schema(self):
                return self._make_schema({"trigger": {"type": "string", "description": "When this rule applies"}, "condition": {"type": "string", "description": "Pattern to match"}, "action": {"type": "string", "description": "What to do when triggered"}, "scope": {"type": "string", "description": "Which contexts (all, coding, planning, etc)"}, "priority": {"type": "integer", "description": "Importance level"}}, required=["trigger", "condition", "action"])
            def execute(self, trigger: str, condition: str, action: str, scope: str = "all", priority: int = 1, **kwargs):
                rule_id = self._sm.add_rule(trigger, condition, action, scope, priority)
                return ToolResult.success_result(data={"rule_id": rule_id})

        class LearnSkillTool(BaseTool):
            name = "learn_skill"
            description = "Learn a dynamic skill from interaction patterns"
            def __init__(self, sm): super().__init__(); self._sm = sm
            def get_schema(self):
                return self._make_schema({"name": {"type": "string", "description": "Skill name"}, "description": {"type": "string", "description": "What this skill does"}, "trigger_patterns": {"type": "array", "items": {"type": "string"}, "description": "Keywords that activate this skill"}, "prompt_addition": {"type": "string", "description": "System prompt addition"}, "examples": {"type": "array", "items": {"type": "string"}, "description": "Usage examples"}, "importance": {"type": "number", "description": "How useful (0.0-1.0)"}}, required=["name", "description", "trigger_patterns", "prompt_addition"])
            def execute(self, name: str, description: str, trigger_patterns: list, prompt_addition: str, examples: list = None, importance: float = 0.5, **kwargs):
                skill_id = self._sm.learn_skill(name, description, trigger_patterns, prompt_addition, examples, None, importance)
                return ToolResult.success_result(data={"skill_id": skill_id})

        class ListRulesTool(BaseTool):
            name = "list_rules"
            description = "List all behavior rules"
            def __init__(self, sm): super().__init__(); self._sm = sm
            def get_schema(self):
                return self._make_schema({})
            def execute(self, **kwargs):
                return ToolResult.success_result(data={"rules": [r.to_dict() for r in self._sm.rules.values()]})

        class ListLearnedSkillsTool(BaseTool):
            name = "list_skills"
            description = "List all learned skills"
            def __init__(self, sm): super().__init__(); self._sm = sm
            def get_schema(self):
                return self._make_schema({})
            def execute(self, **kwargs):
                return ToolResult.success_result(data={"skills": [s.to_dict() for s in self._sm.skills.values()]})

        class GetSkillSuggestionsTool(BaseTool):
            name = "get_skill_suggestions"
            description = "Analyze interactions and suggest new skills to learn"
            def __init__(self, sm): super().__init__(); self._sm = sm
            def get_schema(self):
                return self._make_schema({"recent_interactions": {"type": "array", "items": {"type": "string"}, "description": "List of recent user messages"}}, required=["recent_interactions"])
            def execute(self, recent_interactions: list, **kwargs):
                return ToolResult.success_result(data={"suggestions": self._sm.get_skill_suggestions(recent_interactions)})

        self._tools["add_rule"] = AddRuleTool(skill_memory)
        self._tools["learn_skill"] = LearnSkillTool(skill_memory)
        self._tools["list_rules"] = ListRulesTool(skill_memory)
        self._tools["list_skills"] = ListLearnedSkillsTool(skill_memory)
        self._tools["get_skill_suggestions"] = GetSkillSuggestionsTool(skill_memory)

    @property
    def persona_manager(self) -> PersonaManager:
        """Get the persona manager."""
        return self._persona

    @property
    def capability_registry(self) -> CapabilityRegistry:
        """Get the capability registry."""
        return self._capabilities

    @property
    def hierarchical_memory(self) -> HierarchicalMemory:
        """Get the hierarchical memory."""
        return self._memory

    @property
    def skill_memory_manager(self) -> SkillMemoryManager:
        """Get the skill memory manager."""
        return self._skill_memory

    @property
    def memory_tools(self) -> MemoryToolSet:
        """Get the memory tools wrapper."""
        return self._memory_tools

    def get_files_read(self) -> list[str]:
        """Get list of files read by the toolkit tools."""
        files = []
        if "read_file" in self._tools:
            read_tool = self._tools["read_file"]
            if hasattr(read_tool, "get_files_read"):
                files.extend(read_tool.get_files_read())
        return files