from rest_framework import serializers
from .models import Profile, ProfileRank, RankCategory, GlobalRank, ProfilePackage
from apps.withdraw.serializers import WithdrawSerializer


class RankCategorySerializer(serializers.ModelSerializer):    
    class Meta:
        model = RankCategory
        fields = ['id', 'name', 'min_spending']


class ClaimRankSerializer(serializers.Serializer):
    """র্যাঙ্ক ক্লেইম করার জন্য ইনপুট সিরিয়ালাইজার"""
    rank_category_id = serializers.IntegerField(required=True)
    
    def validate_rank_category_id(self, value):
        try:
            RankCategory.objects.get(id=value)
        except RankCategory.DoesNotExist:
            raise serializers.ValidationError("Invalid rank category ID")
        return value


class ProfileRankSerializer(serializers.ModelSerializer):
    rank_name = serializers.CharField(source='rank_category.name', read_only=True)
    
    class Meta:
        model = ProfileRank
        fields = ['id', 'rank_category', 'rank_name', 'category_rank', 'claimed_at', 'is_active']
        read_only_fields = ['is_active', 'claimed_at', 'category_rank']
    

class GlobalRankSerializer(serializers.ModelSerializer):
    user_name = serializers.CharField(source='profile.user.name', read_only=True)
    user_email = serializers.EmailField(source='profile.user.email', read_only=True)
    
    class Meta:
        model = GlobalRank
        fields = ['id', 'user_name', 'user_email', 'total_spending', 'global_rank']


class ProfileSerializer(serializers.ModelSerializer):
    user_id = serializers.UUIDField(source='user.id', read_only=True)
    user_name = serializers.CharField(source='user.name', read_only=True)
    user_email = serializers.EmailField(source='user.email', read_only=True)
    user_role = serializers.CharField(source='user.role', read_only=True, default='user')
    user_refer_code = serializers.CharField(source='user.refer_code', read_only=True)
    is_active = serializers.BooleanField(source='user.is_active', read_only=True)
    user_refer_link = serializers.SerializerMethodField() 
    
    withdraw_history = WithdrawSerializer(source='user.withdraw_set', many=True, read_only=True)
    
    packages = serializers.SerializerMethodField()
    super_refer_code = serializers.CharField(source='super_refer_code.refer_code', read_only=True, allow_null=True)
    agent_count = serializers.SerializerMethodField()
    downline_stats = serializers.SerializerMethodField()
    earning_breakdown = serializers.SerializerMethodField()
    
    # Package summary fields
    total_packages = serializers.SerializerMethodField()
    total_package_price = serializers.SerializerMethodField()
    
    # Rank-related fields
    current_ranks = serializers.SerializerMethodField()
    claimable_ranks = serializers.SerializerMethodField()
    global_rank_info = serializers.SerializerMethodField()

    class Meta:
        model = Profile
        fields = [
            'id', 'user_id', 'is_active', 'user_name', 'user_email', 'user_role',
            'user_refer_code', 'user_refer_link', 'balance', 'packages', 
            'super_refer_code', 'agent_count', 'downline_stats', 
            'earning_breakdown', 'withdraw_history', 'total_packages', 'total_package_price',
            'current_ranks', 'claimable_ranks', 'global_rank_info'
        ]
        read_only_fields = ['id', 'balance']

    def get_user_refer_link(self, obj):
        return getattr(obj.user, 'referral_url', f"/register?ref={obj.user.refer_code}")

    def get_packages(self, obj):
        packages = []
        profile_packages = ProfilePackage.objects.filter(profile=obj).select_related('package')
        for pp in profile_packages:
            packages.append({
                "name": pp.package.name,
                "price": float(pp.package.price) if hasattr(pp.package, 'price') else 0.0,
                "subscribed_at": pp.subscribed_at,
                "expires_at": pp.expires_at,
                "is_expired": pp.is_expired()
            })
        return packages

    def get_total_packages(self, obj):
        return obj.packages.count()

    def get_total_package_price(self, obj):
        return float(obj.get_total_package_price())

    def get_agent_count(self, obj):
        try:
            return obj.user.referred_profiles_set.count()
        except:
            return 0

    def get_downline_stats(self, obj):
        try:
            return obj.get_downline_stats()
        except:
            return []

    def get_earning_breakdown(self, obj):
        try:
            return obj.get_downline_earning_stats()
        except:
            return {"total_earning": 0, "breakdown": []}
    
    def get_current_ranks(self, obj):
        """Get user's currently active individual ranks"""
        ranks = ProfileRank.objects.filter(
            profile=obj, 
            is_active=True
        ).select_related('rank_category').order_by('rank_category__min_spending')
        return ProfileRankSerializer(ranks, many=True).data

    def get_claimable_ranks(self, obj):
        """Get list of ranks user can claim now based on spending"""
        total_spending = obj.get_total_package_price()
        
        claimed_rank_ids = ProfileRank.objects.filter(
            profile=obj
        ).values_list('rank_category_id', flat=True)
        
        claimable_ranks = RankCategory.objects.exclude(
            id__in=claimed_rank_ids
        ).filter(
            min_spending__lte=total_spending
        ).order_by('min_spending')
        
        return RankCategorySerializer(claimable_ranks, many=True).data

    def get_global_rank_info(self, obj):
        """Get user's global ranking information"""
        try:
            global_rank = GlobalRank.objects.get(profile=obj)
            return GlobalRankSerializer(global_rank).data
        except GlobalRank.DoesNotExist:
            return None

    def to_representation(self, instance):
        data = super().to_representation(instance)
        val = data.get('balance')
        data['balance'] = float(val) if val is not None else 0.0
        return data


class BalanceUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = ['balance']


class ClaimReferralSerializer(serializers.Serializer):
    refer_code = serializers.CharField(required=True, write_only=True)