"""
Сериализаторы для подписок и платежей.
"""
from rest_framework import serializers
from django.utils import timezone
from datetime import timedelta
from .models import SubscriptionPlan, Subscription, Payment, PaymentHistory, SubscriptionUsageLog, PromoCode, BulkDiscount
from apps.users.mixins import TimezoneAwareSerializerMixin


class SubscriptionPlanSerializer(serializers.ModelSerializer):
    """Сериализатор тарифного плана."""
    
    features = serializers.SerializerMethodField()
    bulk_discounts = serializers.SerializerMethodField()
    duration_discounts = serializers.SerializerMethodField()
    available_durations = serializers.SerializerMethodField()
    promo_info = serializers.SerializerMethodField()
    price = serializers.DecimalField(max_digits=10, decimal_places=2, coerce_to_string=False)
    price_per_student = serializers.DecimalField(max_digits=10, decimal_places=2, coerce_to_string=False, allow_null=True)
    
    class Meta:
        model = SubscriptionPlan
        fields = [
            'id',
            'name',
            'slug',
            'description',
            'price',
            'price_per_student',
            'currency',
            'billing_period',
            'subscription_type',
            'trial_days',
            'max_clients',
            'max_lessons_per_month',
            'max_storage_mb',
            'max_video_minutes_per_month',
            'target_role',
            'features',
            'bulk_discounts',
            'duration_discounts',
            'available_durations',
            'promo_info',
            'is_active',
            'is_featured',
            'sort_order',
            'subscribers_count'
        ]
        read_only_fields = ['subscribers_count']
    
    def to_representation(self, instance):
        """Преобразование в представление для API."""
        data = super().to_representation(instance)
        # Преобразуем Decimal в float для JSON
        if data.get('price') is not None:
            data['price'] = float(data['price'])
        if data.get('price_per_student') is not None:
            data['price_per_student'] = float(data['price_per_student'])
        return data
    
    def get_bulk_discounts(self, obj):
        """Получить прогрессирующие скидки для плана."""
        if obj.subscription_type == 'per_student':
            from decimal import Decimal
            discounts = obj.bulk_discounts.all().order_by('min_students')
            result = []
            base_price = obj.price_per_student or obj.price
            
            for discount in discounts:
                # Рассчитываем цену за одного ученика в этом диапазоне
                # total_price - это цена за минимальное количество учеников в диапазоне
                # Например: для диапазона 5-9, total_price = 420 означает 420 руб за 5 учеников
                # Значит цена за одного = 420/5 = 84 руб
                students_for_calc = discount.min_students
                
                price_per_student = discount.total_price / Decimal(str(students_for_calc))
                result.append({
                    'min_students': discount.min_students,
                    'max_students': discount.max_students,
                    'total_price': float(discount.total_price),
                    'price_per_student': float(price_per_student),
                    'base_price': float(base_price)  # Базовая цена для сравнения
                })
            return result
        return []
    
    def get_duration_discounts(self, obj):
        """
        Получить скидки за длительность для плана (определяют доступные периоды оплаты).
        
        ВАЖНО: Периоды, для которых указаны скидки, автоматически становятся доступными для оплаты.
        Скидки применяются только к ежемесячным тарифам (subscription_type='monthly').
        Для тарифов "За ученика" скидки не применяются, но периоды определяют доступные варианты оплаты.
        """
        discounts = obj.duration_discounts.all().order_by('duration_days')
        result = []
        for discount in discounts:
            result.append({
                'duration_days': discount.duration_days,
                'discount_percent': float(discount.discount_percent) if obj.subscription_type == 'monthly' else 0,
                    'months': discount.duration_days / 30,
                'is_available': True,  # Период доступен для оплаты
                'applies_discount': obj.subscription_type == 'monthly',  # Скидка применяется только для monthly
                })
            return result
    
    def get_features(self, obj):
        """Список доступных функций."""
        return {
            'video_calls': obj.allow_video_calls,
            'screen_sharing': obj.allow_screen_sharing,
            'whiteboard': obj.allow_whiteboard,
            'homework': obj.allow_homework,
            'materials': obj.allow_materials,
            'analytics': obj.allow_analytics,
            'telegram_bot': obj.allow_telegram_bot,
            'api_access': obj.allow_api_access,
        }
    
    def get_available_durations(self, obj):
        """Получить доступные периоды оплаты."""
        return obj.get_available_durations()
    
    def get_promo_info(self, obj):
        """Информация об акции."""
        return {
            'promo_type': obj.promo_type,
            'promo_type_display': obj.get_promo_type_display(),
            'max_uses': obj.max_uses,
            'current_uses': obj.current_uses,
            'remaining_uses': obj.max_uses - obj.current_uses if obj.max_uses else None,
            'is_limited': obj.promo_type == 'limited_uses' and obj.max_uses is not None,
            'is_first_time_only': obj.promo_type == 'first_time',
        }


class SubscriptionSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор подписки."""
    
    plan = SubscriptionPlanSerializer(read_only=True)
    is_active_now = serializers.SerializerMethodField()
    days_left = serializers.SerializerMethodField()
    usage = serializers.SerializerMethodField()
    
    class Meta:
        model = Subscription
        fields = [
            'id',
            'user',
            'plan',
            'status',
            'start_date',
            'end_date',
            'trial_end_date',
            'cancelled_at',
            'auto_renew',
            'student_count',
            'is_active_now',
            'days_left',
            'usage',
            'created_at'
        ]
        read_only_fields = ['user', 'created_at']
        timezone_aware_fields = ['start_date', 'end_date', 'trial_end_date', 'cancelled_at', 'created_at']
    
    def get_is_active_now(self, obj):
        """Активна ли подписка сейчас."""
        return obj.is_active()
    
    def get_days_left(self, obj):
        """Дней до истечения."""
        return obj.days_until_expiration()
    
    def get_usage(self, obj):
        """Статистика использования."""
        plan = obj.plan
        
        usage = {
            'lessons': {
                'used': obj.lessons_used,
                'limit': plan.max_lessons_per_month,
                'unlimited': plan.max_lessons_per_month is None
            },
            'storage': {
                'used_mb': obj.storage_used_mb,
                'limit_mb': plan.max_storage_mb,
                'percentage': round((obj.storage_used_mb / plan.max_storage_mb) * 100, 2) if plan.max_storage_mb > 0 else 0
            },
            'video_minutes': {
                'used': obj.video_minutes_used,
                'limit': plan.max_video_minutes_per_month,
                'unlimited': plan.max_video_minutes_per_month is None
            }
        }
        
        return usage


class SubscriptionCreateSerializer(serializers.ModelSerializer):
    """Сериализатор создания подписки."""
    
    plan_id = serializers.IntegerField()
    student_count = serializers.IntegerField(default=0, min_value=0)
    duration_days = serializers.IntegerField(default=30, min_value=1)
    promo_code = serializers.CharField(required=False, allow_blank=True, allow_null=True)
    start_date = serializers.DateTimeField(required=False, allow_null=True)
    
    class Meta:
        model = Subscription
        fields = ['plan_id', 'student_count', 'duration_days', 'promo_code', 'start_date', 'auto_renew']
    
    def validate_plan_id(self, value):
        """Валидация плана."""
        try:
            plan = SubscriptionPlan.objects.get(id=value, is_active=True)
        except SubscriptionPlan.DoesNotExist:
            raise serializers.ValidationError('Тарифный план не найден')
        return value
    
    def validate_duration_days(self, value):
        """Валидация длительности."""
        allowed_durations = [30, 90, 180, 365]
        if value not in allowed_durations:
            raise serializers.ValidationError(
                f'Длительность должна быть одним из значений: {", ".join(map(str, allowed_durations))}'
            )
        
        # Проверяем доступность периода для плана
        plan_id = self.initial_data.get('plan_id')
        if plan_id:
            try:
                plan = SubscriptionPlan.objects.get(id=plan_id)
                if not plan.is_duration_available(value):
                    available = plan.get_available_durations()
                    raise serializers.ValidationError(
                        f'Период {value} дней недоступен для этого тарифа. Доступные периоды: {", ".join(map(str, available))}'
                    )
            except SubscriptionPlan.DoesNotExist:
                pass
        
        return value
    
    def validate_student_count(self, value):
        """Валидация количества учеников."""
        if value < 0:
            raise serializers.ValidationError('Количество учеников не может быть отрицательным')
        return value
    
    def validate(self, attrs):
        """Валидация данных."""
        plan_id = attrs.get('plan_id')
        student_count = attrs.get('student_count', 0)
        
        try:
            plan = SubscriptionPlan.objects.get(id=plan_id)
        except SubscriptionPlan.DoesNotExist:
            raise serializers.ValidationError({'plan_id': 'Тарифный план не найден'})
        
        # Проверяем доступность тарифа (акция)
        user = self.context.get('request').user if self.context.get('request') else None
        can_use, error_message = plan.can_be_used(user)
        if not can_use:
            raise serializers.ValidationError({'plan_id': error_message})
        
        # Для типа "за ученика" количество учеников обязательно
        if plan.subscription_type == 'per_student' and student_count == 0:
            raise serializers.ValidationError({
                'student_count': 'Для подписки "За ученика" необходимо указать количество учеников'
            })
        
        # Для ежемесячной подписки количество учеников должно быть 0
        if plan.subscription_type == 'monthly' and student_count > 0:
            raise serializers.ValidationError({
                'student_count': 'Для ежемесячной подписки количество учеников не требуется'
            })
        
        return attrs
    
    def create(self, validated_data):
        """Создание подписки."""
        from .services import SubscriptionService, PromoCodeService
        
        plan_id = validated_data.pop('plan_id')
        student_count = validated_data.pop('student_count', 0)
        duration_days = validated_data.pop('duration_days', 30)
        promo_code_str = validated_data.pop('promo_code', None)
        start_date = validated_data.pop('start_date', None)
        user = self.context['request'].user
        
        plan = SubscriptionPlan.objects.get(id=plan_id)
        
        # Валидация и применение промокода
        promo_code = None
        if promo_code_str:
            promo_result = PromoCodeService.validate_promo_code(promo_code_str, user)
            if not promo_result['valid']:
                raise serializers.ValidationError({
                    'promo_code': promo_result['error']
                })
            promo_code = promo_result['promo_code']
        
        # Создаем подписку через сервис
        subscription = SubscriptionService.create_subscription(
            user=user,
            plan=plan,
            student_count=student_count,
            duration_days=duration_days,
            start_date=start_date,
            promo_code=promo_code
        )
        
        return subscription


class PaymentSerializer(TimezoneAwareSerializerMixin, serializers.ModelSerializer):
    """Сериализатор платежа."""
    
    subscription = SubscriptionSerializer(read_only=True)
    
    class Meta:
        model = Payment
        fields = [
            'id',
            'uuid',
            'user',
            'subscription',
            'amount',
            'currency',
            'status',
            'payment_method',
            'external_id',
            'description',
            'created_at',
            'paid_at',
            'failed_at',
            'refunded_at'
        ]
        read_only_fields = ['user', 'uuid', 'created_at']
        timezone_aware_fields = ['created_at', 'paid_at', 'failed_at', 'refunded_at']


class PaymentCreateSerializer(serializers.Serializer):
    """Сериализатор создания платежа."""
    
    subscription_id = serializers.IntegerField()
    payment_method = serializers.ChoiceField(choices=Payment.PAYMENT_METHOD_CHOICES)
    return_url = serializers.URLField(required=False)
    
    def validate_subscription_id(self, value):
        """Валидация подписки."""
        try:
            subscription = Subscription.objects.get(id=value)
            # Проверяем что подписка принадлежит пользователю
            if subscription.user != self.context['request'].user:
                raise serializers.ValidationError('Подписка не найдена')
        except Subscription.DoesNotExist:
            raise serializers.ValidationError('Подписка не найдена')
        
        return value
    
    def create(self, validated_data):
        """Создание платежа."""
        user = self.context['request'].user
        subscription_id = validated_data['subscription_id']
        payment_method = validated_data['payment_method']
        
        subscription = Subscription.objects.get(id=subscription_id)
        
        # Создаем платеж
        payment = Payment.objects.create(
            user=user,
            subscription=subscription,
            amount=subscription.plan.price,
            currency=subscription.plan.currency,
            payment_method=payment_method,
            description=f"Оплата подписки {subscription.plan.name}"
        )
        
        return payment


class PaymentHistorySerializer(serializers.ModelSerializer):
    """Сериализатор истории платежа."""
    
    class Meta:
        model = PaymentHistory
        fields = ['id', 'status', 'message', 'data', 'created_at']
        read_only_fields = ['created_at']


class SubscriptionUsageLogSerializer(serializers.ModelSerializer):
    """Сериализатор лога использования."""
    
    class Meta:
        model = SubscriptionUsageLog
        fields = ['id', 'usage_type', 'amount', 'description', 'created_at']
        read_only_fields = ['created_at']
