"""
Base Rich Choice Objects

This module defines the core dataclass structures for rich choice objects.
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Any


class ChoiceCategory(Enum):
    """Categories for organizing choice types"""

    STATUS = "status"
    TYPE = "type"
    CLASSIFICATION = "classification"
    PREFERENCE = "preference"
    PERMISSION = "permission"
    PRIORITY = "priority"
    ACTION = "action"
    NOTIFICATION = "notification"
    MODERATION = "moderation"
    TECHNICAL = "technical"
    BUSINESS = "business"
    SECURITY = "security"
    OTHER = "other"


@dataclass(frozen=True)
class RichChoice:
    """
    Rich choice object with metadata support.

    This replaces simple tuple choices with a comprehensive object that can
    carry additional information like descriptions, colors, icons, and custom metadata.

    Attributes:
        value: The stored value (equivalent to first element of tuple choice)
        label: Human-readable display name (equivalent to second element of tuple choice)
        description: Detailed description of what this choice means
        metadata: Dictionary of additional properties (colors, icons, etc.)
        deprecated: Whether this choice is deprecated and should not be used for new entries
        category: Category for organizing related choices
    """

    value: str
    label: str
    description: str = ""
    metadata: dict[str, Any] = field(default_factory=dict)
    deprecated: bool = False
    category: ChoiceCategory = ChoiceCategory.OTHER

    def __post_init__(self):
        """Validate the choice object after initialization"""
        if not self.value:
            raise ValueError("Choice value cannot be empty")
        if not self.label:
            raise ValueError("Choice label cannot be empty")

    @property
    def color(self) -> str | None:
        """Get the color from metadata if available"""
        return self.metadata.get("color")

    @property
    def icon(self) -> str | None:
        """Get the icon from metadata if available"""
        return self.metadata.get("icon")

    @property
    def css_class(self) -> str | None:
        """Get the CSS class from metadata if available"""
        return self.metadata.get("css_class")

    @property
    def sort_order(self) -> int:
        """Get the sort order from metadata, defaulting to 0"""
        return self.metadata.get("sort_order", 0)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary representation for API serialization"""
        return {
            "value": self.value,
            "label": self.label,
            "description": self.description,
            "metadata": self.metadata,
            "deprecated": self.deprecated,
            "category": self.category.value,
            "color": self.color,
            "icon": self.icon,
            "css_class": self.css_class,
            "sort_order": self.sort_order,
        }

    def __str__(self) -> str:
        return self.label

    def __repr__(self) -> str:
        return f"RichChoice(value='{self.value}', label='{self.label}')"


@dataclass
class ChoiceGroup:
    """
    A group of related choices with shared metadata.

    This allows for organizing choices into logical groups with
    common properties and behaviors.
    """

    name: str
    choices: list[RichChoice]
    description: str = ""
    metadata: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self):
        """Validate the choice group after initialization"""
        if not self.name:
            raise ValueError("Choice group name cannot be empty")
        if not self.choices:
            raise ValueError("Choice group must contain at least one choice")

        # Validate that all choice values are unique within the group
        values = [choice.value for choice in self.choices]
        if len(values) != len(set(values)):
            raise ValueError("All choice values within a group must be unique")

    def get_choice(self, value: str) -> RichChoice | None:
        """Get a choice by its value"""
        for choice in self.choices:
            if choice.value == value:
                return choice
        return None

    def get_choices_by_category(self, category: ChoiceCategory) -> list[RichChoice]:
        """Get all choices in a specific category"""
        return [choice for choice in self.choices if choice.category == category]

    def get_active_choices(self) -> list[RichChoice]:
        """Get all non-deprecated choices"""
        return [choice for choice in self.choices if not choice.deprecated]

    def to_tuple_choices(self) -> list[tuple[str, str]]:
        """Convert to legacy tuple choices format"""
        return [(choice.value, choice.label) for choice in self.choices]

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary representation for API serialization"""
        return {
            "name": self.name,
            "description": self.description,
            "metadata": self.metadata,
            "choices": [choice.to_dict() for choice in self.choices],
        }
