"""
DRF Serializers for Rich Choices

This module provides Django REST Framework serializer implementations
for rich choice objects.
"""

from typing import Any

from rest_framework import serializers

from .base import ChoiceGroup, RichChoice
from .registry import registry


class RichChoiceSerializer(serializers.Serializer):
    """
    Serializer for individual RichChoice objects.

    This provides a consistent API representation for choice objects
    with all their metadata.
    """

    value = serializers.CharField()
    label = serializers.CharField()
    description = serializers.CharField()
    metadata = serializers.DictField()
    deprecated = serializers.BooleanField()
    category = serializers.CharField()
    color = serializers.CharField(allow_null=True)
    icon = serializers.CharField(allow_null=True)
    css_class = serializers.CharField(allow_null=True)
    sort_order = serializers.IntegerField()

    def to_representation(self, instance: RichChoice) -> dict[str, Any]:
        """Convert RichChoice to dictionary representation"""
        return instance.to_dict()


class RichChoiceOptionSerializer(serializers.Serializer):
    """
    Serializer for choice options in filter endpoints.

    This replaces the legacy FilterOptionSerializer with rich choice support.
    """

    value = serializers.CharField()
    label = serializers.CharField()
    description = serializers.CharField(allow_blank=True)
    count = serializers.IntegerField(required=False, allow_null=True)
    selected = serializers.BooleanField(default=False)
    deprecated = serializers.BooleanField(default=False)
    color = serializers.CharField(allow_null=True, required=False)
    icon = serializers.CharField(allow_null=True, required=False)
    css_class = serializers.CharField(allow_null=True, required=False)
    metadata = serializers.DictField(required=False)

    def to_representation(self, instance) -> dict[str, Any]:
        """Convert choice option to dictionary representation"""
        if isinstance(instance, RichChoice):
            # Convert RichChoice to option format
            return {
                "value": instance.value,
                "label": instance.label,
                "description": instance.description,
                "count": None,
                "selected": False,
                "deprecated": instance.deprecated,
                "color": instance.color,
                "icon": instance.icon,
                "css_class": instance.css_class,
                "metadata": instance.metadata,
            }
        elif isinstance(instance, dict):
            # Handle dictionary input (for backwards compatibility)
            return {
                "value": instance.get("value", ""),
                "label": instance.get("label", ""),
                "description": instance.get("description", ""),
                "count": instance.get("count"),
                "selected": instance.get("selected", False),
                "deprecated": instance.get("deprecated", False),
                "color": instance.get("color"),
                "icon": instance.get("icon"),
                "css_class": instance.get("css_class"),
                "metadata": instance.get("metadata", {}),
            }
        else:
            return super().to_representation(instance)


class ChoiceGroupSerializer(serializers.Serializer):
    """
    Serializer for ChoiceGroup objects.

    This provides API representation for entire choice groups
    with all their choices and metadata.
    """

    name = serializers.CharField()
    description = serializers.CharField()
    metadata = serializers.DictField()
    choices = RichChoiceSerializer(many=True)

    def to_representation(self, instance: ChoiceGroup) -> dict[str, Any]:
        """Convert ChoiceGroup to dictionary representation"""
        return instance.to_dict()


class RichChoiceFieldSerializer(serializers.CharField):
    """
    Serializer field for rich choice values.

    This field serializes the choice value but can optionally
    include rich choice metadata in the response.
    """

    def __init__(self, choice_group: str, domain: str = "core", include_metadata: bool = False, **kwargs):
        """
        Initialize the serializer field.

        Args:
            choice_group: Name of the choice group in the registry
            domain: Domain namespace for the choice group
            include_metadata: Whether to include rich choice metadata
            **kwargs: Additional arguments passed to CharField
        """
        self.choice_group = choice_group
        self.domain = domain
        self.include_metadata = include_metadata
        super().__init__(**kwargs)

    def to_representation(self, value: str) -> Any:
        """Convert choice value to representation"""
        if not value:
            return value

        if self.include_metadata:
            # Return rich choice object
            choice = registry.get_choice(self.choice_group, value, self.domain)
            if choice:
                return RichChoiceSerializer(choice).data
            else:
                # Fallback for unknown values
                return {
                    "value": value,
                    "label": value,
                    "description": "",
                    "metadata": {},
                    "deprecated": False,
                    "category": "other",
                    "color": None,
                    "icon": None,
                    "css_class": None,
                    "sort_order": 0,
                }
        else:
            # Return just the value
            return value

    def to_internal_value(self, data: Any) -> str:
        """Convert input data to choice value"""
        if isinstance(data, dict) and "value" in data:
            # Handle rich choice object input
            return data["value"]
        else:
            # Handle string input
            return super().to_internal_value(data)


def create_choice_options_serializer(
    choice_group: str, domain: str = "core", include_counts: bool = False, queryset=None, count_field: str = "id"
) -> list[dict[str, Any]]:
    """
    Create choice options for filter endpoints.

    This function generates choice options with optional counts
    for use in filter metadata endpoints.

    Args:
        choice_group: Name of the choice group in the registry
        domain: Domain namespace for the choice group
        include_counts: Whether to include counts for each option
        queryset: QuerySet to count against (required if include_counts=True)
        count_field: Field to filter on for counting (default: 'id')

    Returns:
        List of choice option dictionaries
    """
    choices = registry.get_active_choices(choice_group, domain)
    options = []

    for choice in choices:
        option_data = {
            "value": choice.value,
            "label": choice.label,
            "description": choice.description,
            "selected": False,
            "deprecated": choice.deprecated,
            "color": choice.color,
            "icon": choice.icon,
            "css_class": choice.css_class,
            "metadata": choice.metadata,
        }

        if include_counts and queryset is not None:
            # Count items for this choice
            try:
                count = queryset.filter(**{count_field: choice.value}).count()
                option_data["count"] = count
            except Exception:
                # If counting fails, set count to None
                option_data["count"] = None
        else:
            option_data["count"] = None

        options.append(option_data)

    # Sort by sort_order, then by label
    options.sort(
        key=lambda x: (
            (lambda c: c.sort_order if (c is not None and hasattr(c, "sort_order")) else 0)(
                registry.get_choice(choice_group, x["value"], domain)
            ),
            x["label"],
        )
    )

    return options


def serialize_choice_value(value: str, choice_group: str, domain: str = "core", include_metadata: bool = False) -> Any:
    """
    Serialize a single choice value.

    Args:
        value: The choice value to serialize
        choice_group: Name of the choice group in the registry
        domain: Domain namespace for the choice group
        include_metadata: Whether to include rich choice metadata

    Returns:
        Serialized choice value (string or rich object)
    """
    if not value:
        return value

    if include_metadata:
        choice = registry.get_choice(choice_group, value, domain)
        if choice:
            return RichChoiceSerializer(choice).data
        else:
            # Fallback for unknown values
            return {
                "value": value,
                "label": value,
                "description": "",
                "metadata": {},
                "deprecated": False,
                "category": "other",
                "color": None,
                "icon": None,
                "css_class": None,
                "sort_order": 0,
            }
    else:
        return value
