"""
Registry system for managing tools, resources, and prompts.

Provides centralized registration and discovery of MCP components.
"""

import logging

from .base import BasePrompt, BaseResource, BaseTool, PromptMetadata, ResourceMetadata, ToolMetadata

logger = logging.getLogger(__name__)


class ToolRegistry:
    """Registry for managing MCP tools"""

    def __init__(self):
        self._tools: dict[str, type[BaseTool]] = {}
        self._metadata: dict[str, ToolMetadata] = {}
        self._instances: dict[str, BaseTool] = {}

    def register(self, tool_class: type[BaseTool], metadata: ToolMetadata) -> None:
        """
        Register a tool class with metadata.

        Args:
            tool_class: Tool class to register
            metadata: Tool metadata
        """
        name = metadata.name

        if name in self._tools:
            logger.warning(f"Tool '{name}' is already registered, overwriting")

        self._tools[name] = tool_class
        self._metadata[name] = metadata

        logger.info(f"Registered tool: {name} (category: {metadata.category})")

    def get_tool(self, name: str) -> BaseTool | None:
        """
        Get a tool instance by name.

        Args:
            name: Tool name

        Returns:
            Tool instance or None if not found
        """
        if name not in self._tools:
            return None

        # Create singleton instance
        if name not in self._instances:
            tool_class = self._tools[name]
            metadata = self._metadata[name]
            self._instances[name] = tool_class(metadata.name, metadata.description)

        return self._instances[name]

    def list_tools(self, category: str | None = None) -> list[ToolMetadata]:
        """
        List all registered tools, optionally filtered by category.

        Args:
            category: Optional category filter

        Returns:
            List of tool metadata
        """
        if category:
            return [meta for meta in self._metadata.values() if meta.category == category]
        return list(self._metadata.values())

    def get_metadata(self, name: str) -> ToolMetadata | None:
        """
        Get tool metadata by name.

        Args:
            name: Tool name

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

    def unregister(self, name: str) -> bool:
        """
        Unregister a tool.

        Args:
            name: Tool name

        Returns:
            True if tool was unregistered, False if not found
        """
        if name not in self._tools:
            return False

        del self._tools[name]
        del self._metadata[name]
        if name in self._instances:
            del self._instances[name]

        logger.info(f"Unregistered tool: {name}")
        return True


class ResourceRegistry:
    """Registry for managing MCP resources"""

    def __init__(self):
        self._resources: dict[str, type[BaseResource]] = {}
        self._metadata: dict[str, ResourceMetadata] = {}
        self._instances: dict[str, BaseResource] = {}

    def register(self, resource_class: type[BaseResource], metadata: ResourceMetadata) -> None:
        """
        Register a resource class with metadata.

        Args:
            resource_class: Resource class to register
            metadata: Resource metadata
        """
        uri = metadata.uri

        if uri in self._resources:
            logger.warning(f"Resource '{uri}' is already registered, overwriting")

        self._resources[uri] = resource_class
        self._metadata[uri] = metadata

        logger.info(f"Registered resource: {uri} (category: {metadata.category})")

    def register_instance(
        self, resource_instance: BaseResource, metadata: ResourceMetadata
    ) -> None:
        """
        Register a specific resource instance with metadata.

        This preserves constructor-specific state (e.g., file paths) that cannot be
        reconstructed from generic metadata alone.

        Args:
            resource_instance: Concrete resource instance to register
            metadata: Resource metadata
        """
        uri = metadata.uri

        # Store both the class and the concrete instance
        self._resources[uri] = type(resource_instance)
        self._metadata[uri] = metadata
        self._instances[uri] = resource_instance

        logger.info(f"Registered resource instance: {uri} (category: {metadata.category})")

    def get_resource(self, uri: str) -> BaseResource | None:
        """
        Get a resource instance by URI.

        Args:
            uri: Resource URI

        Returns:
            Resource instance or None if not found
        """
        if uri not in self._resources:
            return None

        # Create singleton instance
        if uri not in self._instances:
            resource_class = self._resources[uri]
            metadata = self._metadata[uri]
            self._instances[uri] = resource_class(
                metadata.uri, metadata.name, metadata.description, metadata.mime_type
            )

        return self._instances[uri]

    def list_resources(self, category: str | None = None) -> list[ResourceMetadata]:
        """
        List all registered resources, optionally filtered by category.

        Args:
            category: Optional category filter

        Returns:
            List of resource metadata
        """
        if category:
            return [meta for meta in self._metadata.values() if meta.category == category]
        return list(self._metadata.values())

    def get_metadata(self, uri: str) -> ResourceMetadata | None:
        """
        Get resource metadata by URI.

        Args:
            uri: Resource URI

        Returns:
            Resource metadata or None if not found
        """
        return self._metadata.get(uri)


class PromptRegistry:
    """Registry for managing MCP prompts"""

    def __init__(self):
        self._prompts: dict[str, type[BasePrompt]] = {}
        self._metadata: dict[str, PromptMetadata] = {}
        self._instances: dict[str, BasePrompt] = {}

    def register(self, prompt_class: type[BasePrompt], metadata: PromptMetadata) -> None:
        """
        Register a prompt class with metadata.

        Args:
            prompt_class: Prompt class to register
            metadata: Prompt metadata
        """
        name = metadata.name

        if name in self._prompts:
            logger.warning(f"Prompt '{name}' is already registered, overwriting")

        self._prompts[name] = prompt_class
        self._metadata[name] = metadata

        logger.info(f"Registered prompt: {name} (category: {metadata.category})")

    def get_prompt(self, name: str) -> BasePrompt | None:
        """
        Get a prompt instance by name.

        Args:
            name: Prompt name

        Returns:
            Prompt instance or None if not found
        """
        if name not in self._prompts:
            return None

        # Create singleton instance
        if name not in self._instances:
            prompt_class = self._prompts[name]
            metadata = self._metadata[name]
            self._instances[name] = prompt_class(metadata.name, metadata.description)

        return self._instances[name]

    def list_prompts(self, category: str | None = None) -> list[PromptMetadata]:
        """
        List all registered prompts, optionally filtered by category.

        Args:
            category: Optional category filter

        Returns:
            List of prompt metadata
        """
        if category:
            return [meta for meta in self._metadata.values() if meta.category == category]
        return list(self._metadata.values())

    def get_metadata(self, name: str) -> PromptMetadata | None:
        """
        Get prompt metadata by name.

        Args:
            name: Prompt name

        Returns:
            Prompt metadata or None if not found
        """
        return self._metadata.get(name)


# Global registry instances
tool_registry = ToolRegistry()
resource_registry = ResourceRegistry()
prompt_registry = PromptRegistry()
