"""Self-modification tools for Open Agent.

These tools allow the agent to learn from user interactions,
manage its own capabilities, and evolve over time.
"""

from typing import TYPE_CHECKING, List, Optional
from pathlib import Path
import json

from ..tools.base import BaseTool, ToolResult, ToolCategory

if TYPE_CHECKING:
    from .persona import PersonaManager
    from .capabilities import CapabilityRegistry, Capability


class LearnPreferenceTool(BaseTool):
    """Tool for learning user preferences."""

    name = "learn_preference"
    description = "Store a user preference for future reference. Use when the user explicitly asks you to remember something about their preferences."
    category = ToolCategory.LEARNING

    def __init__(self, persona_manager: "PersonaManager"):
        super().__init__()
        self._persona = persona_manager

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "context": {
                    "type": "string",
                    "description": "The context/category for this preference (e.g., 'python.framework', 'communication.style')",
                },
                "preference": {
                    "type": "string",
                    "description": "The preference value (e.g., 'fastapi', 'concise')",
                },
                "confidence": {
                    "type": "number",
                    "description": "Confidence level (0.0-1.0) in this preference",
                    "default": 1.0,
                },
            },
            required=["context", "preference"],
        )

    def execute(self, context: str, preference: str, confidence: float = 1.0) -> ToolResult:
        try:
            self._persona.learn_preference(context, preference, confidence)
            return ToolResult(
                success=True,
                data={
                    "message": f"Learned preference: {context} = {preference}",
                    "context": context,
                    "preference": preference,
                    "total_preferences": len(self._persona.preferences),
                },
            )
        except Exception as e:
            return ToolResult(
                success=False,
                error=f"Failed to learn preference: {str(e)}",
            )


class AddCapabilityTool(BaseTool):
    """Tool for adding new capabilities."""

    name = "add_capability"
    description = "Add a new capability based on user needs. Use when the user wants you to consistently handle certain types of requests in a specific way."
    category = ToolCategory.LEARNING

    def __init__(self, capability_registry: "CapabilityRegistry"):
        super().__init__()
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "name": {
                    "type": "string",
                    "description": "Short name for this capability (e.g., 'pr-review-helper')",
                },
                "description": {
                    "type": "string",
                    "description": "Description of what this capability does",
                },
                "trigger_patterns": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Phrases that trigger this capability (e.g., ['review.*pr', 'pull request'])",
                },
                "tools": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Tools this capability uses (optional)",
                    "default": [],
                },
                "prompt_addition": {
                    "type": "string",
                    "description": "Additional guidance to add to your system prompt when this capability is active",
                },
                "examples": {
                    "type": "array",
                    "items": {"type": "string"},
                    "description": "Example interactions (optional)",
                    "default": [],
                },
            },
            required=["name", "description", "trigger_patterns", "prompt_addition"],
        )

    def execute(
        self,
        name: str,
        description: str,
        trigger_patterns: List[str],
        prompt_addition: str,
        tools: Optional[List[str]] = None,
        examples: Optional[List[str]] = None,
    ) -> ToolResult:
        try:
            from .capabilities import Capability

            capability = Capability(
                name=name,
                description=description,
                trigger_patterns=trigger_patterns,
                tools=tools or [],
                prompt_addition=prompt_addition,
                examples=examples or [],
            )

            self._registry.register(capability)

            return ToolResult(
                success=True,
                data={
                    "message": f"Added capability: {name}",
                    "capability": name,
                    "total_capabilities": len(self._registry.capabilities),
                },
            )
        except ValueError as e:
            return ToolResult(
                success=False,
                error=str(e),
            )
        except Exception as e:
            return ToolResult(
                success=False,
                error=f"Failed to add capability: {str(e)}",
            )


class RemoveCapabilityTool(BaseTool):
    """Tool for removing capabilities."""

    name = "remove_capability"
    description = "Remove a previously learned capability. Use when the user asks you to forget a specific behavior or capability."
    category = ToolCategory.LEARNING

    def __init__(self, capability_registry: "CapabilityRegistry"):
        super().__init__()
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "name": {
                    "type": "string",
                    "description": "Name of the capability to remove",
                },
            },
            required=["name"],
        )

    def execute(self, name: str) -> ToolResult:
        if self._registry.unregister(name):
            return ToolResult(
                success=True,
                data={
                    "message": f"Removed capability: {name}",
                    "remaining_capabilities": len(self._registry.capabilities),
                },
            )
        else:
            return ToolResult(
                success=False,
                error=f"Capability '{name}' not found",
            )


class ListCapabilitiesTool(BaseTool):
    """Tool for listing capabilities."""

    name = "list_capabilities"
    description = "List all learned capabilities with their usage statistics. Use when the user asks what you know or what you can do."
    category = ToolCategory.LEARNING

    def __init__(self, capability_registry: "CapabilityRegistry"):
        super().__init__()
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "show_details": {
                    "type": "boolean",
                    "description": "Show full details for each capability",
                    "default": False,
                },
            },
        )

    def execute(self, show_details: bool = False) -> ToolResult:
        capabilities = self._registry.list_all()

        if not capabilities:
            return ToolResult(
                success=True,
                data={
                    "message": "No capabilities learned yet.",
                    "capabilities": [],
                    "count": 0,
                },
            )

        if show_details:
            caps_data = [
                {
                    "name": c.name,
                    "description": c.description,
                    "usage_count": c.usage_count,
                    "enabled": c.enabled,
                    "trigger_patterns": c.trigger_patterns,
                }
                for c in capabilities
            ]
        else:
            caps_data = [
                {
                    "name": c.name,
                    "description": c.description,
                    "usage_count": c.usage_count,
                    "enabled": c.enabled,
                }
                for c in capabilities
            ]

        return ToolResult(
            success=True,
            data={
                "capabilities": caps_data,
                "count": len(capabilities),
                "active": sum(1 for c in capabilities if c.enabled),
            },
        )


class ExportPersonaTool(BaseTool):
    """Tool for exporting persona data."""

    name = "export_persona"
    description = "Export the learned persona (preferences and capabilities) to a file for backup or sharing."
    category = ToolCategory.LEARNING

    def __init__(
        self,
        persona_manager: "PersonaManager",
        capability_registry: "CapabilityRegistry",
    ):
        super().__init__()
        self._persona = persona_manager
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to export file (optional, defaults to persona-export.json)",
                },
                "include_capabilities": {
                    "type": "boolean",
                    "description": "Include capabilities in export",
                    "default": True,
                },
            },
        )

    def execute(
        self,
        file_path: Optional[str] = None,
        include_capabilities: bool = True,
    ) -> ToolResult:
        try:
            export_path = Path(file_path) if file_path else Path("persona-export.json")

            data = {
                "persona": self._persona.export_persona(),
            }

            if include_capabilities:
                data["capabilities"] = self._registry.export()

            with open(export_path, "w") as f:
                json.dump(data, f, indent=2)

            return ToolResult(
                success=True,
                data={
                    "message": f"Exported persona to {export_path}",
                    "file_path": str(export_path),
                    "preferences_count": len(self._persona.preferences),
                    "capabilities_count": len(self._registry.capabilities) if include_capabilities else 0,
                },
            )
        except Exception as e:
            return ToolResult(
                success=False,
                error=f"Failed to export persona: {str(e)}",
            )


class ImportPersonaTool(BaseTool):
    """Tool for importing persona data."""

    name = "import_persona"
    description = "Import a persona from a file. This will replace current preferences and capabilities."
    category = ToolCategory.LEARNING

    def __init__(
        self,
        persona_manager: "PersonaManager",
        capability_registry: "CapabilityRegistry",
    ):
        super().__init__()
        self._persona = persona_manager
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "file_path": {
                    "type": "string",
                    "description": "Path to import file",
                },
                "merge": {
                    "type": "boolean",
                    "description": "Merge with existing preferences instead of replacing",
                    "default": False,
                },
            },
            required=["file_path"],
        )

    def execute(self, file_path: str, merge: bool = False) -> ToolResult:
        try:
            import_path = Path(file_path)
            if not import_path.exists():
                return ToolResult(
                    success=False,
                    error=f"File not found: {file_path}",
                )

            with open(import_path, "r") as f:
                data = json.load(f)

            # Import persona
            if "persona" in data:
                if merge:
                    # Merge preferences
                    for key, pref_data in data["persona"].get("preferences", {}).items():
                        if key not in self._persona.preferences:
                            self._persona.learn_preference(
                                key, pref_data["value"], pref_data.get("confidence", 1.0)
                            )
                else:
                    self._persona.import_persona(data["persona"])

            # Import capabilities
            if "capabilities" in data and not merge:
                self._registry.import_data(data["capabilities"])

            return ToolResult(
                success=True,
                data={
                    "message": f"Imported persona from {file_path}",
                    "merge": merge,
                    "preferences_count": len(self._persona.preferences),
                    "capabilities_count": len(self._registry.capabilities),
                },
            )
        except json.JSONDecodeError:
            return ToolResult(
                success=False,
                error=f"Invalid JSON in file: {file_path}",
            )
        except Exception as e:
            return ToolResult(
                success=False,
                error=f"Failed to import persona: {str(e)}",
            )


class SuggestSkillTool(BaseTool):
    """Tool for suggesting skill creation from conversation."""

    name = "suggest_skill"
    description = "Analyze recent conversation and suggest creating a reusable skill from it. Use when you notice a pattern that could be reusable."
    category = ToolCategory.LEARNING

    def __init__(
        self,
        persona_manager: "PersonaManager",
        capability_registry: "CapabilityRegistry",
    ):
        super().__init__()
        self._persona = persona_manager
        self._registry = capability_registry

    def get_schema(self) -> dict:
        return self._make_schema(
            properties={
                "description": {
                    "type": "string",
                    "description": "Description of the skill to suggest",
                },
                "conversation_summary": {
                    "type": "string",
                    "description": "Summary of the conversation that led to this suggestion",
                },
            },
            required=["description"],
        )

    def execute(self, description: str, conversation_summary: str = "") -> ToolResult:
        # This tool is mainly for recording suggestions
        # The actual skill creation would happen through user confirmation
        return ToolResult(
            success=True,
            data={
                "message": "Skill suggestion recorded",
                "description": description,
                "conversation_summary": conversation_summary,
                "suggestion": {
                    "type": "skill_creation",
                    "needs_confirmation": True,
                    "description": description,
                },
            },
        )