"""
Choice Registry

Centralized registry for managing all choice definitions across the application.
"""

from typing import Any

from django.core.exceptions import ImproperlyConfigured

from .base import ChoiceGroup, RichChoice


class ChoiceRegistry:
    """
    Centralized registry for managing all choice definitions.

    This provides a single source of truth for all choice objects
    throughout the application, with support for namespacing by domain.
    """

    def __init__(self):
        self._choices: dict[str, ChoiceGroup] = {}
        self._domains: dict[str, list[str]] = {}

    def register(
        self,
        name: str,
        choices: list[RichChoice],
        domain: str = "core",
        description: str = "",
        metadata: dict[str, Any] | None = None,
    ) -> ChoiceGroup:
        """
        Register a group of choices.

        Args:
            name: Unique name for the choice group
            choices: List of RichChoice objects
            domain: Domain namespace (e.g., 'rides', 'parks', 'accounts')
            description: Description of the choice group
            metadata: Additional metadata for the group

        Returns:
            The registered ChoiceGroup

        Raises:
            ImproperlyConfigured: If name is already registered with different choices
        """
        full_name = f"{domain}.{name}"

        if full_name in self._choices:
            # Check if the existing registration is identical
            existing_group = self._choices[full_name]
            existing_values = [choice.value for choice in existing_group.choices]
            new_values = [choice.value for choice in choices]

            if existing_values == new_values:
                # Same choices, return existing group (allow duplicate registration)
                return existing_group
            else:
                # Different choices, this is an error
                raise ImproperlyConfigured(
                    f"Choice group '{full_name}' is already registered with different choices. "
                    f"Existing: {existing_values}, New: {new_values}"
                )

        choice_group = ChoiceGroup(name=full_name, choices=choices, description=description, metadata=metadata or {})

        self._choices[full_name] = choice_group

        # Track domain
        if domain not in self._domains:
            self._domains[domain] = []
        self._domains[domain].append(name)

        return choice_group

    def get(self, name: str, domain: str = "core") -> ChoiceGroup | None:
        """Get a choice group by name and domain"""
        full_name = f"{domain}.{name}"
        return self._choices.get(full_name)

    def get_choice(self, group_name: str, value: str, domain: str = "core") -> RichChoice | None:
        """Get a specific choice by group name, value, and domain"""
        choice_group = self.get(group_name, domain)
        if choice_group:
            return choice_group.get_choice(value)
        return None

    def get_choices(self, name: str, domain: str = "core") -> list[RichChoice]:
        """Get all choices in a group"""
        choice_group = self.get(name, domain)
        return choice_group.choices if choice_group else []

    def get_active_choices(self, name: str, domain: str = "core") -> list[RichChoice]:
        """Get all non-deprecated choices in a group"""
        choice_group = self.get(name, domain)
        return choice_group.get_active_choices() if choice_group else []

    def get_domains(self) -> list[str]:
        """Get all registered domains"""
        return list(self._domains.keys())

    def get_domain_choices(self, domain: str) -> dict[str, ChoiceGroup]:
        """Get all choice groups for a specific domain"""
        if domain not in self._domains:
            return {}

        return {name: self._choices[f"{domain}.{name}"] for name in self._domains[domain]}

    def list_all(self) -> dict[str, ChoiceGroup]:
        """Get all registered choice groups"""
        return self._choices.copy()

    def validate_choice(self, group_name: str, value: str, domain: str = "core") -> bool:
        """Validate that a choice value exists in a group"""
        choice = self.get_choice(group_name, value, domain)
        return choice is not None and not choice.deprecated

    def get_choice_display(self, group_name: str, value: str, domain: str = "core") -> str:
        """Get the display label for a choice value"""
        choice = self.get_choice(group_name, value, domain)
        if choice:
            return choice.label
        else:
            raise ValueError(f"Choice value '{value}' not found in group '{group_name}' for domain '{domain}'")

    def clear_domain(self, domain: str) -> None:
        """Clear all choices for a specific domain (useful for testing)"""
        if domain in self._domains:
            for name in self._domains[domain]:
                full_name = f"{domain}.{name}"
                if full_name in self._choices:
                    del self._choices[full_name]
            del self._domains[domain]

    def clear_all(self) -> None:
        """Clear all registered choices (useful for testing)"""
        self._choices.clear()
        self._domains.clear()


# Global registry instance
registry = ChoiceRegistry()


def register_choices(
    name: str,
    choices: list[RichChoice],
    domain: str = "core",
    description: str = "",
    metadata: dict[str, Any] | None = None,
) -> ChoiceGroup:
    """
    Convenience function to register choices with the global registry.

    Args:
        name: Unique name for the choice group
        choices: List of RichChoice objects
        domain: Domain namespace
        description: Description of the choice group
        metadata: Additional metadata for the group

    Returns:
        The registered ChoiceGroup
    """
    return registry.register(name, choices, domain, description, metadata)


def get_choices(name: str, domain: str = "core") -> list[RichChoice]:
    """Get choices from the global registry"""
    return registry.get_choices(name, domain)


def get_choice(group_name: str, value: str, domain: str = "core") -> RichChoice | None:
    """Get a specific choice from the global registry"""
    return registry.get_choice(group_name, value, domain)


def validate_choice(group_name: str, value: str, domain: str = "core") -> bool:
    """Validate a choice value using the global registry"""
    return registry.validate_choice(group_name, value, domain)


def get_choice_display(group_name: str, value: str, domain: str = "core") -> str:
    """Get choice display label using the global registry"""
    return registry.get_choice_display(group_name, value, domain)
