from .models import *
from rest_framework import serializers
from django.utils import timezone
from datetime import timedelta
from django.contrib.auth.models import AnonymousUser


class DetailSerializer(serializers.ModelSerializer):
    texts = serializers.SerializerMethodField()

    class Meta:
        model = DetailModel
        exclude = ['detail_model', 'detail_text1',
                   'detail_text2', 'detail_text3', 'detail_text4']

    def get_texts(self, obj):
        return [
            text for text in [
                obj.detail_text1,
                obj.detail_text2,
                obj.detail_text3,
                obj.detail_text4,
            ] if text
        ]


class ProductDetailSerializer(serializers.ModelSerializer):
    details = DetailSerializer(many=True, read_only=True)
    detail_category = serializers.StringRelatedField()

    class Meta:
        model = ProductDetailModel
        exclude = ['name']


class AttributeTypeSerialzier(serializers.ModelSerializer):
    class Meta:
        model = AttributeType
        fields = "__all__"


class AttributeValueSerialzier(serializers.ModelSerializer):
    attribute_type = AttributeTypeSerialzier()

    class Meta:
        model = AttributeValue
        fields = "__all__"


class InPackItemsSerialzier(serializers.ModelSerializer):
    class Meta:
        model = InPackItems
        fields = '__all__'


class ProductImageSerailizer(serializers.ModelSerializer):
    class Meta:
        model = ProductImageModel
        fields = '__all__'


class ProductVariantSerialzier(serializers.ModelSerializer):
    product_attributes = AttributeValueSerialzier(many=True)
    in_pack_items = InPackItemsSerialzier(many=True)
    images = ProductImageSerailizer(many=True)
    details = ProductDetailSerializer(many=True, read_only=True)
    cart_quantity = serializers.SerializerMethodField()
    price = serializers.SerializerMethodField()
    price_after_discount = serializers.SerializerMethodField()
    special_discount_amount = serializers.SerializerMethodField()
    special_discount_link = serializers.SerializerMethodField()

    class Meta:
        model = ProductVariant
        exclude = ('min_price', 'sell', 'currency', 'product', 'input_price', 'price_in_dollor', 'profit', 'special_discount_percent')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        view_type = self.context.get('view_type', None)
        if view_type == 'list':
            self.fields.pop('in_pack_items', None)

    def get_special_discount_amount(self, obj):
        if obj.special_discount_percent:
            special_discount_amount = obj.profit * (obj.special_discount_percent / 100)
            return f'{special_discount_amount:,.0f} تومانءءء'
        else:
            return None
    
    def get_special_discount_link(self, obj):
        request = self.context.get('request')
        if request.user.is_authenticated:
            return 'https://google.com'
        else:
            return None

    def get_price_after_discount(self, obj):
        return f'{obj.price_after_discount:,.0f} تومانءءء'

    def get_cart_quantity(self, obj):
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return 0
        cart_items = self.context.get('cart_items', [])
        if cart_items:
            for item in cart_items:
                if item['product']['id'] == obj.id:
                    return item['quantity']
        return 0

    def get_price(self, obj):
        return f'{obj.price:,.0f} تومانءءء'


class SubCategorySerializer(serializers.ModelSerializer):
    product_count = serializers.SerializerMethodField()
    parent = serializers.SerializerMethodField()

    class Meta:
        model = SubCategoryModel
        fields = ['id', 'name', 'slug', 'icon', 'meta_title',
                  'meta_description', 'product_count', 'parent', 'image']

    def get_product_count(self, obj):
        # Use annotated product_count from database annotation
        return getattr(obj, 'product_count', 0)

    def get_parent(self, obj):
        return obj.parent.name if obj.parent else None


class UnitCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = UnitCategoryModel
        fields = ['id', 'name', 'slug', 'icon', 'meta_title',
                  'meta_description', 'image']


class MainCategorySerializer(serializers.ModelSerializer):
    subcategorys = SubCategorySerializer(many=True)

    class Meta:
        model = MainCategoryModel
        fields = ['id', 'name', 'slug', 'icon', 'meta_title',
                  'meta_description', 'subcategorys', 'image', 'video']


class DynamicProductSerializer(serializers.ModelSerializer):
    variants = serializers.SerializerMethodField()
    colors = serializers.SerializerMethodField()
    category = SubCategorySerializer(read_only=True)
    is_new = serializers.SerializerMethodField()
    related_products = serializers.SerializerMethodField()
    added_to_favorites = serializers.SerializerMethodField()
    best_deal_price_before_discount = serializers.SerializerMethodField()
    best_deal_price_after_discount = serializers.SerializerMethodField()
    best_deal_discount = serializers.SerializerMethodField()
    main_image = serializers.SerializerMethodField()
    customer_pickup_title = serializers.SerializerMethodField()
    customer_pickup_description = serializers.SerializerMethodField()
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        view_type = self.context.get('view_type', 'all')
        if view_type != 'all':
            allowed_fields = self.Meta.view_type[view_type]
            allowed = set(allowed_fields)
            existing = set(self.fields.keys())

            for field_name in existing - allowed:
                self.fields.pop(field_name)

    class Meta:
        model = ProductModel
        fields = "__all__"
        view_type = {
            'list': ['id', 'name', 'rating', 'slug', 'category',  'colors', 'image', 'best_deal_price_before_discount', 'best_deal_price_after_discount', 'best_deal_discount', 'main_image'],
            'slider': ['id', 'name', 'rating', 'slug', 'category', 'variants', 'colors', 'image', 'best_deal_price_before_discount', 'best_deal_price_after_discount', 'best_deal_discount', ],
            'instance': ['id', 'name', 'description', 'rating',  'slug', 'meta_description', 'meta_keywords', 'meta_rating', 'category', 'related_products', 'in_pack_items', 'variants', 'colors', 'added_to_favorites', 'image', 'customer_pickup_title', 'customer_pickup_description'],
            'chat': ['id', 'name', 'description', 'variants', 'image']
        }

    def _get_best_deal_variant(self, obj):
        """Get best deal variant from prefetched variants (pre-ordered by discount/price)"""
        if not hasattr(self, '_best_deal_cache'):
            self._best_deal_cache = {}
        
        if obj.id not in self._best_deal_cache:
            # Get first from prefetched variants (already ordered by discount desc, price asc)
            variants = list(obj.variants.all())
            self._best_deal_cache[obj.id] = variants[0] if variants else None
        
        return self._best_deal_cache[obj.id]

    def get_main_image(self, obj):
        if obj.image:
            return obj.image.url
        # Use prefetched variants
        variants = list(obj.variants.all())
        if variants:
            images = list(variants[0].images.all())
            if images:
                return images[0].image.url
        return None

    def get_best_deal_price_before_discount(self, obj):
        best_deal = self._get_best_deal_variant(obj)
        if best_deal:
            return f'{best_deal.price:,.0f} تومانءءء'
        return 0
    
    def get_best_deal_price_after_discount(self, obj):
        best_deal = self._get_best_deal_variant(obj)
        if best_deal:
            price_after_discount = best_deal.price_after_discount
            return f'{price_after_discount:,.0f} تومانءءء'
        return 0
    
    def get_best_deal_discount(self, obj):
        best_deal = self._get_best_deal_variant(obj)
        if best_deal:
            return best_deal.discount
        return 0

    def get_customer_pickup_title(self, obj):
        if obj.shop:
            return obj.shop.customer_pickup_title
        return None

    def get_customer_pickup_description(self, obj):
        if obj.shop:
            return obj.shop.customer_pickup_description
        return None

    def get_added_to_favorites(self, obj):
        from account.models import UserFavorites
        request = self.context.get('request')
        if not request or not request.user.is_authenticated:
            return False

        # Use exists() with filter instead of fetching all products
        return UserFavorites.objects.filter(user=request.user, products=obj).exists()

    def get_variants(self, obj):
        view_type = self.context.get('view_type')
        if view_type == 'slider':
            varients = obj.variants.filter(slider_category__isnull=False)
        else:
            varients = obj.variants.all()
        return ProductVariantSerialzier(instance=varients, many=True, context=self.context).data

    def get_colors(self, obj):
        # Get colors from prefetched variants efficiently
        variants = list(obj.variants.all())
        colors = set()
        for variant in variants:
            if variant.color:
                colors.add(variant.color)
        return list(colors)

    def get_is_new(self, obj):
        return timezone.now() < obj.created_at + timedelta(days=7)

    def get_related_products(self, obj):
        if obj.related_products.all().count() >= 5:
            related_products = obj.related_products.all()[:10]
        else:
            related_products = obj.category.products.exclude(id=obj.id)[:10]

        serializer = DynamicProductSerializer(
            related_products,
            many=True,
            context={
                'view_type': 'list',
                'request': self.context.get('request')
            }
        )
        return serializer.data


class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = CommentModel
        exclude = ('review_status', )
        read_only_fields = ('review_status', 'product', 'user')


class BotProductSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductModel
        fields = [
            'pk',
            'name'
        ]
