"""Catalog Engine — DRF serializers.

Replaces manual dict serialization in views.py with proper DRF ModelSerializers
for CatalogCategory, CatalogItem, and CatalogItemVersion.
"""

from __future__ import annotations

from rest_framework import serializers

from simorgh.apps.catalog.models import (
    CatalogCategory,
    CatalogItem,
    CatalogItemStatus,
    CatalogItemVersion,
    CatalogType,
)


# ---------------------------------------------------------------------------
# CatalogCategory
# ---------------------------------------------------------------------------

class CatalogCategoryListSerializer(serializers.ModelSerializer):
    """Compact category representation for lists and trees."""

    parent_name = serializers.CharField(source="parent.name", read_only=True, default=None)

    class Meta:
        model = CatalogCategory
        fields = (
            "id", "public_id", "name", "slug", "catalog_type",
            "parent_id", "parent_name", "description", "icon",
            "sort_order", "is_active", "created_at",
        )
        read_only_fields = ("id", "public_id", "created_at")


class CatalogCategoryDetailSerializer(CatalogCategoryListSerializer):
    """Full category representation including children count."""

    children_count = serializers.IntegerField(source="children.count", read_only=True, default=0)
    items_count = serializers.IntegerField(source="items.count", read_only=True, default=0)

    class Meta(CatalogCategoryListSerializer.Meta):
        fields = CatalogCategoryListSerializer.Meta.fields + (
            "children_count", "items_count",
        )


class CatalogCategoryWriteSerializer(serializers.ModelSerializer):
    """Create/update serializer for CatalogCategory."""

    class Meta:
        model = CatalogCategory
        fields = (
            "name", "slug", "catalog_type", "parent_id",
            "description", "icon", "sort_order", "is_active",
        )

    def validate_catalog_type(self, value: str) -> str:
        valid = [ct.value for ct in CatalogType]
        if value not in valid:
            raise serializers.ValidationError(
                f"Invalid catalog type. Allowed: {valid}"
            )
        return value


# ---------------------------------------------------------------------------
# CatalogItem
# ---------------------------------------------------------------------------

class CatalogItemListSerializer(serializers.ModelSerializer):
    """Compact catalog item for lists."""

    catalog_type_display = serializers.CharField(source="get_catalog_type_display", read_only=True)
    status_display = serializers.CharField(source="get_status_display", read_only=True)
    category_name = serializers.CharField(source="category.name", read_only=True, default=None)
    owner_name = serializers.SerializerMethodField()

    class Meta:
        model = CatalogItem
        fields = (
            "id", "public_id", "name", "slug", "catalog_type",
            "catalog_type_display", "category_id", "category_name",
            "short_description", "status", "status_display",
            "owner_id", "owner_name", "published_at", "retired_at",
            "image_id", "created_at", "updated_at",
        )
        read_only_fields = (
            "id", "public_id", "catalog_type_display", "status_display",
            "category_name", "owner_name", "created_at", "updated_at",
        )

    def get_owner_name(self, obj: CatalogItem) -> str | None:
        if obj.owner_id:
            return obj.owner.get_full_name() or obj.owner.email
        return None


class CatalogItemDetailSerializer(CatalogItemListSerializer):
    """Full catalog item detail including description, AI fields, versions."""

    version_count = serializers.IntegerField(source="versions.count", read_only=True, default=0)
    related_items_data = serializers.SerializerMethodField()

    class Meta(CatalogItemListSerializer.Meta):
        fields = CatalogItemListSerializer.Meta.fields + (
            "description", "related_items", "related_items_data",
            "documentation_content_id", "ai_description", "ai_semantic_type",
            "version_count", "workflow_instance_id",
        )

    def get_related_items_data(self, obj: CatalogItem) -> list[dict]:
        if not obj.related_items:
            return []
        related = CatalogItem.objects.filter(
            tenant_id=obj.tenant_id,
            public_id__in=obj.related_items,
            status=CatalogItemStatus.PUBLISHED,
        ).select_related("category")[:20]
        return [
            {
                "public_id": str(r.public_id),
                "name": r.name,
                "catalog_type": r.catalog_type,
                "status": r.status,
            }
            for r in related
        ]


class CatalogItemWriteSerializer(serializers.ModelSerializer):
    """Create/update serializer for CatalogItem."""

    class Meta:
        model = CatalogItem
        fields = (
            "name", "slug", "catalog_type", "category_id",
            "owner_id", "description", "short_description",
            "image_id", "related_items", "documentation_content_id",
            "ai_description", "ai_semantic_type",
        )

    def validate_catalog_type(self, value: str) -> str:
        valid = [ct.value for ct in CatalogType]
        if value not in valid:
            raise serializers.ValidationError(
                f"Invalid catalog type. Allowed: {valid}"
            )
        return value


# ---------------------------------------------------------------------------
# CatalogItemVersion
# ---------------------------------------------------------------------------

class CatalogItemVersionSerializer(serializers.ModelSerializer):
    """Version snapshot serializer."""

    changed_by_name = serializers.SerializerMethodField()

    class Meta:
        model = CatalogItemVersion
        fields = (
            "id", "public_id", "catalog_item_id", "version",
            "name", "description", "status", "changed_by_id",
            "changed_by_name", "change_summary", "created_at",
        )
        read_only_fields = ("id", "public_id", "created_at")

    def get_changed_by_name(self, obj: CatalogItemVersion) -> str | None:
        if obj.changed_by_id:
            return obj.changed_by.get_full_name() or obj.changed_by.email
        return None
