"""
API views для платежей с интеграцией ЮKassa.
"""
import logging
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny
from django.conf import settings
from django.utils import timezone

from .models import Payment, Subscription
from .yookassa_service import yookassa_service

logger = logging.getLogger(__name__)


class PaymentViewSet(viewsets.ViewSet):
    """
    ViewSet для управления платежами через ЮKassa.
    """
    permission_classes = [IsAuthenticated]
    
    @action(detail=False, methods=['post'])
    def create_payment(self, request):
        """
        Создать платеж для подписки.
        
        POST /api/subscriptions/payments/create_payment/
        Body: {
            "plan_id": 1,
            "student_count": 5,  // для типа "за ученика"
            "duration_days": 30,  // 30, 90, 180, 365
            "promo_code": "WELCOME10",  // опционально
            "return_url": "http://localhost:3000/payment/success"
        }
        """
        from .models import SubscriptionPlan
        from .services import SubscriptionService, PromoCodeService
        from datetime import timedelta
        
        plan_id = request.data.get('plan_id')
        return_url = request.data.get('return_url') or f"{settings.FRONTEND_URL}/payment/success"
        student_count = request.data.get('student_count', 0)
        duration_days = request.data.get('duration_days', 30)
        promo_code_str = request.data.get('promo_code')
        is_renewal = request.data.get('is_renewal', False)
        is_add_students = request.data.get('is_add_students', False)
        subscription_id = request.data.get('subscription_id')
        
        if not plan_id:
            return Response(
                {'error': 'Требуется plan_id'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            # Получаем план подписки
            plan = SubscriptionPlan.objects.get(id=plan_id, is_active=True)
            
            # Валидация для типа "за ученика"
            if plan.subscription_type == 'per_student':
                if not student_count or student_count <= 0:
                    return Response(
                        {'error': 'Для подписки "за ученика" необходимо указать количество учеников'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            
            # Валидация промокода если указан
            promo_code = None
            if promo_code_str:
                promo_result = PromoCodeService.validate_promo_code(promo_code_str, request.user)
                if not promo_result['valid']:
                    return Response(
                        {'error': promo_result['error']},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                promo_code = promo_result['promo_code']
            
            # Если это продление, получаем существующую подписку
            existing_subscription = None
            remaining_days = None
            current_student_count = 0
            actual_students_count = 0
            if is_renewal and subscription_id:
                try:
                    existing_subscription = Subscription.objects.get(
                        id=subscription_id,
                        user=request.user,
                        plan=plan
                    )
                    # Рассчитываем оставшиеся дни
                    if existing_subscription.end_date:
                        now = timezone.now()
                        if existing_subscription.end_date > now:
                            delta = existing_subscription.end_date - now
                            remaining_days = max(0, delta.days)
                    # Получаем текущее количество учеников из подписки
                    current_student_count = existing_subscription.student_count or 0
                    
                    # Получаем фактическое количество учеников в системе
                    from apps.users.models import Client
                    actual_students_count = Client.objects.filter(mentors=request.user).count()
                    
                    # Если подписка истекла и пользователь не указал количество учеников,
                    # используем фактическое количество (но не меньше текущего оплаченного)
                    if plan.subscription_type == 'per_student' and not student_count:
                        # Если подписка истекла, используем фактическое количество студентов
                        if not existing_subscription.is_active():
                            student_count = max(actual_students_count, current_student_count)
                        else:
                            # Если подписка активна, используем текущее оплаченное количество
                            student_count = current_student_count if current_student_count > 0 else actual_students_count
                    
                    # Если пользователь указал количество меньше фактического, корректируем
                    if plan.subscription_type == 'per_student' and student_count < actual_students_count:
                        student_count = actual_students_count
                except Subscription.DoesNotExist:
                    pass
            
            # Рассчитываем цену с учетом оставшихся дней и текущего количества учеников
            price_data = SubscriptionService.calculate_subscription_price(
                plan=plan,
                student_count=student_count,
                duration_days=duration_days,
                promo_code=promo_code,
                remaining_days=remaining_days,
                current_student_count=current_student_count
            )
            
            final_amount = price_data['final_amount']
            
            # Если это добавление учеников в текущий период
            if is_add_students and existing_subscription:
                # Обновляем только количество учеников, не продлеваем подписку
                if plan.subscription_type == 'per_student':
                    existing_subscription.student_count = student_count
                    existing_subscription.unpaid_students_count = 0
                    existing_subscription.pending_payment_amount = 0
                
                # Обновляем суммы платежа
                existing_subscription.original_amount = price_data['original_amount']
                existing_subscription.discount_amount = price_data['discount_amount']
                existing_subscription.final_amount = price_data['final_amount']
                if promo_code:
                    existing_subscription.promo_code = promo_code
                existing_subscription.save()
                subscription = existing_subscription
            # Если это продление, обновляем существующую подписку
            elif is_renewal and existing_subscription:
                # Обновляем количество учеников если изменилось
                if plan.subscription_type == 'per_student':
                    existing_subscription.student_count = student_count
                    existing_subscription.unpaid_students_count = 0
                    existing_subscription.pending_payment_amount = 0
                
                # Продлеваем подписку: добавляем дни к текущей end_date
                if existing_subscription.end_date:
                    # Если end_date в будущем, добавляем к нему
                    if existing_subscription.end_date > timezone.now():
                        existing_subscription.end_date = existing_subscription.end_date + timedelta(days=duration_days)
                    else:
                        # Если подписка уже истекла, начинаем с текущей даты
                        existing_subscription.start_date = timezone.now()
                        existing_subscription.end_date = timezone.now() + timedelta(days=duration_days)
                else:
                    existing_subscription.end_date = timezone.now() + timedelta(days=duration_days)
                
                existing_subscription.duration_days = duration_days
                existing_subscription.status = 'active'
                existing_subscription.original_amount = price_data['original_amount']
                existing_subscription.discount_amount = price_data['discount_amount']
                existing_subscription.final_amount = price_data['final_amount']
                if promo_code:
                    existing_subscription.promo_code = promo_code
                existing_subscription.save()
                subscription = existing_subscription
            else:
                # Создаем новую подписку
                subscription = SubscriptionService.create_subscription(
                    user=request.user,
                    plan=plan,
                    student_count=student_count,
                    duration_days=duration_days,
                    start_date=timezone.now(),
                    promo_code=promo_code
                )
            
            # Создаем платеж в ЮKassa
            yookassa_payment = yookassa_service.create_payment(
                amount=float(final_amount),
                description=f"Оплата подписки: {plan.name}" + 
                           (f" ({student_count} учеников)" if plan.subscription_type == 'per_student' else ''),
                return_url=return_url,
                metadata={
                    'subscription_id': subscription.id,
                    'user_id': request.user.id,
                    'plan_id': plan.id,
                    'student_count': student_count if plan.subscription_type == 'per_student' else None,
                    'duration_days': duration_days,
                }
            )
            
            # Сохраняем платеж в БД
            payment = Payment.objects.create(
                user=request.user,
                subscription=subscription,
                amount=final_amount,
                currency='RUB',
                status='pending',
                payment_method='yookassa',
                external_id=yookassa_payment['id'],
                description=f"Оплата подписки: {plan.name}" + 
                           (f" ({student_count} учеников)" if plan.subscription_type == 'per_student' else ''),
                provider_response={
                    'confirmation_url': yookassa_payment['confirmation_url'],
                    'yookassa_status': yookassa_payment['status'],
                    'metadata': yookassa_payment['metadata'],
                },
            )
            
            logger.info(f"Payment created: {payment.id} for user {request.user.id}, amount: {final_amount}")
            
            return Response({
                'success': True,
                'payment_id': payment.id,
                'external_id': payment.external_id,
                'confirmation_url': yookassa_payment['confirmation_url'],
                'amount': float(payment.amount),
            }, status=status.HTTP_201_CREATED)
        
        except SubscriptionPlan.DoesNotExist:
            return Response(
                {'error': 'План подписки не найден'},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            logger.error(f"Error creating payment: {e}", exc_info=True)
            return Response(
                {'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=True, methods=['get'])
    def check_status(self, request, pk=None):
        """
        Проверить статус платежа.
        
        GET /api/subscriptions/payments/{id}/check_status/
        """
        try:
            payment = Payment.objects.get(id=pk, user=request.user)
        except Payment.DoesNotExist:
            return Response(
                {'error': 'Платеж не найден'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        try:
            # Получаем актуальный статус из ЮKassa
            yookassa_payment = yookassa_service.get_payment(payment.external_id)
            
            # Обновляем статус в БД
            old_status = payment.status
            yookassa_status = yookassa_payment['status']
            
            if yookassa_status == 'succeeded' and old_status != 'succeeded':
                payment.status = 'succeeded'
                payment.paid_at = timezone.now()
                payment.provider_response['payment_method'] = yookassa_payment.get('payment_method')
                payment.save()
                
                # Активируем подписку
                if payment.subscription:
                    payment.subscription.status = 'active'
                    payment.subscription.start_date = timezone.now()
                    payment.subscription.save()
            
            elif yookassa_status == 'canceled':
                payment.status = 'cancelled'
                payment.save()
            
            return Response({
                'id': payment.id,
                'status': payment.status,
                'external_id': payment.external_id,
                'amount': float(payment.amount),
                'created_at': payment.created_at,
                'paid_at': payment.paid_at,
            })
        
        except Exception as e:
            logger.error(f"Error checking payment status: {e}")
            return Response(
                {'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['post'], permission_classes=[AllowAny])
    def webhook(self, request):
        """
        Webhook для получения уведомлений от ЮKassa.
        
        POST /api/subscriptions/payments/webhook/
        """
        try:
            # Получаем данные из запроса
            data = request.data
            event_type = data.get('event')
            payment_object = data.get('object', {})
            payment_id = payment_object.get('id')
            
            if not payment_id:
                return Response(
                    {'error': 'Payment ID not found'},
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # Находим платеж в БД
            try:
                payment = Payment.objects.get(external_id=payment_id)
            except Payment.DoesNotExist:
                logger.warning(f"Payment {payment_id} not found in database")
                return Response({'status': 'ok'}, status=status.HTTP_200_OK)
            
            # Обрабатываем событие
            if event_type == 'payment.succeeded':
                payment_method = payment_object.get('payment_method', {}).get('type')
                payment.status = 'succeeded'
                payment.paid_at = timezone.now()
                payment.provider_response['payment_method'] = payment_method
                payment.provider_response['webhook_data'] = data
                payment.save()
                
                # Активируем подписку
                if payment.subscription:
                    payment.subscription.status = 'active'
                    payment.subscription.start_date = timezone.now()
                    payment.subscription.save()
                
                logger.info(f"Payment {payment_id} succeeded")
            
            elif event_type == 'payment.canceled':
                cancellation_details = payment_object.get('cancellation_details', {})
                reason = cancellation_details.get('reason', '')
                payment.status = 'cancelled'
                payment.provider_response['cancellation_reason'] = reason
                payment.provider_response['webhook_data'] = data
                payment.save()
                logger.info(f"Payment {payment_id} canceled: {reason}")
            
            elif event_type == 'payment.waiting_for_capture':
                payment.status = 'processing'
                payment.save()
            
            return Response({'status': 'ok'}, status=status.HTTP_200_OK)
        
        except Exception as e:
            logger.error(f"Error processing webhook: {e}")
            return Response(
                {'error': str(e)},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['get'])
    def history(self, request):
        """
        История платежей пользователя.
        
        GET /api/subscriptions/payments/history/
        """
        payments = Payment.objects.filter(user=request.user).select_related(
            'subscription',
            'subscription__plan'
        ).order_by('-created_at')
        
        return Response({
            'payments': [
                {
                    'id': p.id,
                    'amount': float(p.amount),
                    'currency': p.currency,
                    'status': p.status,
                    'payment_method': p.payment_method,
                    'description': p.description,
                    'plan_name': p.subscription.plan.name if p.subscription else None,
                    'created_at': p.created_at,
                    'paid_at': p.paid_at,
                }
                for p in payments
            ]
        })


