"""
Installment Payment Views - Handle customer setup and management of installment payments
"""
import logging
from decimal import Decimal
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.views.decorators.http import require_http_methods
from django.http import JsonResponse
from django.utils import timezone
from dateutil.relativedelta import relativedelta
    
# Create order with installment details
from django.conf import settings
from .models import (
    Order, InstallmentSchedule, ScheduledPayment, 
    RecurringPaymentToken, Cart, CartItem
)
from .flutterwave_service import FlutterwaveService
from .forms import InstallmentSetupForm

logger = logging.getLogger(__name__)


@login_required
@require_http_methods(["GET", "POST"])
def checkout_with_installment(request):
    """
    Step 1: Customer selects installment option during checkout
    Calculates monthly payment amount and shows payment options
    """
    user = request.user
    
    # Get user's cart
    try:
        cart = Cart.objects.get(user=user)
        if not cart.cartitem_set.exists():
            messages.error(request, "Your cart is empty")
            return redirect('shop:cart')
    except Cart.DoesNotExist:
        messages.error(request, "Your cart is empty")
        return redirect('shop:cart')
    
    # Calculate cart total
    subtotal = sum(item.product.price * item.quantity for item in cart.cartitem_set.all())
    
    if request.method == 'GET':
        # Show checkout with installment options
        context = {
            'cart': cart,
            'subtotal': subtotal,
            'payment_options': [
                {'months': 1, 'label': 'Full Payment (Today)'},
                {'months': 3, 'label': '3 Monthly Payments'},
                {'months': 6, 'label': '6 Monthly Payments'},
                {'months': 12, 'label': '12 Monthly Payments'},
            ]
        }
        return render(request, 'shop/checkout_installment.html', context)
    
    # POST - Process installment selection
    num_installments = int(request.POST.get('num_installments', 1))
    
    if num_installments < 1 or num_installments > 12:
        messages.error(request, "Invalid number of installments")
        return redirect('shop:checkout_installment')

    order = Order.objects.create(
        user=user,
        total=subtotal,
        status='Pending',
        payment_type='installment' if num_installments > 1 else 'full',
        total_installments=num_installments,
        shipping_address=user.profile.shipping_address if hasattr(user.profile, 'shipping_address') else None
    )
    
    # Create order items
    for cart_item in cart.cartitem_set.all():
        OrderItem.objects.create(
            order=order,
            product=cart_item.product,
            quantity=cart_item.quantity,
            price=cart_item.product.price
        )
    
    # Clear cart
    cart.cartitem_set.all().delete()
    
    # Redirect to payment setup
    if num_installments > 1:
        return redirect('shop:setup_installment_payment', order_id=order.id)
    else:
        return redirect('shop:payment_checkout', order_id=order.id)


@login_required
@require_http_methods(["GET", "POST"])
def setup_installment_payment(request, order_id):
    """
    Step 2: Customer sets up recurring payment authorization
    Customer enters card details and authorizes recurring charges
    """
    order = get_object_or_404(Order, id=order_id, user=request.user)
    
    if order.payment_type == 'full':
        messages.error(request, "This order is not set up for installments")
        return redirect('shop:order_detail', order_id=order.id)
    
    if request.method == 'GET':
        # Show payment authorization form
        flutterwave_service = FlutterwaveService()
        
        # Initiate payment authorization
        auth_response = flutterwave_service.initiate_payment(
            amount=Decimal('0.01'),  # Minimal amount for authorization
            email=request.user.email,
            phone=request.user.profile.phone or '',
            order_reference=f"AUTH-ORDER-{order.id}",
            customer_name=request.user.get_full_name() or request.user.username,
        )
        
        if auth_response['status'] != 'success':
            messages.error(request, "Could not initialize payment. Please try again.")
            logger.error(f"Payment initialization failed: {auth_response['message']}")
            return redirect('shop:order_detail', order_id=order.id)
        
        context = {
            'order': order,
            'authorization_url': auth_response['authorization_url'],
            'monthly_payment': Decimal(order.total) / Decimal(order.total_installments),
            'num_installments': order.total_installments,
        }
        return render(request, 'shop/setup_installment.html', context)
    
    # POST - Confirm payment authorization
    transaction_reference = request.POST.get('transaction_reference', '')
    
    if not transaction_reference:
        messages.error(request, "Payment authorization failed")
        return redirect('shop:setup_installment_payment', order_id=order.id)
    
    # Verify the authorization transaction
    flutterwave_service = FlutterwaveService()
    verify_response = flutterwave_service.verify_transaction(transaction_reference)
    
    if not verify_response['verified']:
        messages.error(request, "Payment authorization could not be verified")
        logger.warning(f"Authorization verification failed for order {order.id}")
        return redirect('shop:setup_installment_payment', order_id=order.id)
    
    # Extract card token from verification response
    # Note: You need to save the token from Flutterwave's response
    card_token = verify_response.get('gateway_response', {}).get('data', {}).get('token', '')
    
    if not card_token:
        messages.error(request, "Could not extract payment token. Please try again.")
        return redirect('shop:setup_installment_payment', order_id=order.id)
    
    # Save or get the recurring payment token
    gateway_response = verify_response.get('gateway_response', {})
    card_data = gateway_response.get('data', {}).get('card', {})
    
    payment_token, created = RecurringPaymentToken.objects.get_or_create(
        user=request.user,
        flutterwave_token=card_token,
        defaults={
            'card_last_four': card_data.get('last_4digits', 'XXXX'),
            'card_brand': card_data.get('type', 'Unknown'),
            'gateway': 'flutterwave',
            'is_authorized': True,
            'authorized_at': timezone.now(),
            'is_active': True,
        }
    )
    
    if created:
        payment_token.is_authorized = True
        payment_token.authorized_at = timezone.now()
        payment_token.save()
    
    # Update order with token
    order.flutterwave_token = card_token
    order.status = 'Paid'  # First payment is authorized
    order.installments_paid = 1
    order.save()
    
    # Create installment schedule
    monthly_amount = Decimal(order.total) / Decimal(order.total_installments)
    
    installment_schedule = InstallmentSchedule.objects.create(
        order=order,
        payment_token=payment_token,
        installment_amount=monthly_amount,
        total_installments=order.total_installments,
        paid_installments=1,  # First payment is authorized
        start_date=timezone.now().date(),
        next_payment_date=(timezone.now() + relativedelta(months=1)).date(),
        final_payment_date=(timezone.now() + relativedelta(months=order.total_installments)).date(),
        status='active',
        auto_retry=True,
    )
    
    # Create scheduled payment records for all remaining installments
    for i in range(2, order.total_installments + 1):
        due_date = timezone.now() + relativedelta(months=i - 1)
        ScheduledPayment.objects.create(
            installment_schedule=installment_schedule,
            order=order,
            amount=monthly_amount,
            installment_number=i,
            status='pending',
            scheduled_date=timezone.now().date(),
            due_date=due_date.date(),
        )
    
    messages.success(
        request,
        f"Payment setup successful! Your card will be charged ${monthly_amount:.2f} "
        f"each month for {order.total_installments} months."
    )
    return redirect('shop:order_detail', order_id=order.id)


@login_required
def installment_schedule_detail(request, order_id):
    """
    Display detailed installment payment schedule for a customer
    Shows all upcoming payments and payment history
    """
    order = get_object_or_404(Order, id=order_id, user=request.user)
    
    if not hasattr(order, 'installment_schedule'):
        messages.error(request, "This order does not have an installment schedule")
        return redirect('shop:order_detail', order_id=order.id)
    
    installment_schedule = order.installment_schedule
    scheduled_payments = installment_schedule.scheduled_payments.all().order_by('due_date')
    
    # Separate paid and upcoming payments
    paid_payments = scheduled_payments.filter(status='successful')
    upcoming_payments = scheduled_payments.filter(status__in=['pending', 'processing'])
    failed_payments = scheduled_payments.filter(status='failed')
    
    context = {
        'order': order,
        'installment_schedule': installment_schedule,
        'paid_payments': paid_payments,
        'upcoming_payments': upcoming_payments,
        'failed_payments': failed_payments,
        'total_paid': installment_schedule.paid_installments * installment_schedule.installment_amount,
        'remaining_balance': installment_schedule.remaining_installments * installment_schedule.installment_amount,
    }
    
    return render(request, 'shop/installment_schedule.html', context)


@login_required
def retry_failed_payment(request, payment_id):
    """
    Allow customer to manually retry a failed payment
    """
    scheduled_payment = get_object_or_404(ScheduledPayment, id=payment_id)
    
    # Verify customer owns this order
    if scheduled_payment.order.user != request.user:
        messages.error(request, "Unauthorized access")
        return redirect('shop:my_orders')
    
    if scheduled_payment.status != 'failed':
        messages.error(request, "This payment has not failed")
        return redirect('shop:installment_schedule_detail', 
                       order_id=scheduled_payment.order.id)
    
    if request.method == 'GET':
        # Show retry confirmation page
        context = {
            'payment': scheduled_payment,
            'order': scheduled_payment.order,
        }
        return render(request, 'shop/retry_payment.html', context)
    
    # POST - Attempt retry
    flutterwave_service = FlutterwaveService()
    installment_schedule = scheduled_payment.installment_schedule
    
    # Attempt to charge the saved card
    charge_response = flutterwave_service.charge_recurring_card(
        amount=scheduled_payment.amount,
        email=request.user.email,
        token=installment_schedule.payment_token.flutterwave_token,
        order_reference=f"RETRY-{scheduled_payment.order.id}-{scheduled_payment.installment_number}",
        installment_num=scheduled_payment.installment_number,
        customer_name=request.user.get_full_name() or request.user.username,
    )
    
    if charge_response['status'] == 'success':
        # Mark as successful
        scheduled_payment.mark_as_successful(
            transaction_ref=charge_response['transaction_ref'],
            gateway_response=charge_response.get('gateway_response', {})
        )
        
        # Update installment schedule
        installment_schedule.paid_installments += 1
        if installment_schedule.is_complete:
            installment_schedule.status = 'completed'
        installment_schedule.save()
        
        messages.success(request, "Payment retry successful!")
    else:
        messages.error(
            request,
            f"Payment retry failed: {charge_response['message']}"
        )
        logger.error(f"Retry charge failed for payment {payment_id}: {charge_response}")
    
    return redirect('shop:installment_schedule_detail', 
                   order_id=scheduled_payment.order.id)


@login_required
def update_payment_method(request, order_id):
    """
    Allow customer to update their payment method for future installments
    """
    order = get_object_or_404(Order, id=order_id, user=request.user)
    
    if not hasattr(order, 'installment_schedule'):
        messages.error(request, "This order does not have an installment schedule")
        return redirect('shop:order_detail', order_id=order.id)
    
    installment_schedule = order.installment_schedule
    
    if request.method == 'GET':
        context = {
            'order': order,
            'installment_schedule': installment_schedule,
        }
        return render(request, 'shop/update_payment_method.html', context)
    
    # POST - Update payment method
    flutterwave_service = FlutterwaveService()
    
    # Initiate new authorization
    auth_response = flutterwave_service.initiate_payment(
        amount=Decimal('0.01'),
        email=request.user.email,
        phone=request.user.profile.phone or '',
        order_reference=f"UPDATE-ORDER-{order.id}",
        customer_name=request.user.get_full_name() or request.user.username,
    )
    
    if auth_response['status'] != 'success':
        messages.error(request, "Could not initialize payment authorization")
        return render(request, 'shop/update_payment_method.html', {
            'order': order,
            'error': auth_response['message']
        })
    
    context = {
        'order': order,
        'authorization_url': auth_response['authorization_url'],
    }
    return render(request, 'shop/confirm_payment_update.html', context)


@login_required
def confirm_payment_update(request):
    """
    Confirm updated payment method
    """
    if request.method != 'POST':
        return redirect('shop:my_orders')
    
    order_id = request.POST.get('order_id')
    transaction_reference = request.POST.get('transaction_reference')
    
    order = get_object_or_404(Order, id=order_id, user=request.user)
    installment_schedule = order.installment_schedule
    
    # Verify new authorization
    flutterwave_service = FlutterwaveService()
    verify_response = flutterwave_service.verify_transaction(transaction_reference)
    
    if not verify_response['verified']:
        messages.error(request, "Payment method update verification failed")
        return redirect('shop:update_payment_method', order_id=order.id)
    
    # Extract new card token
    card_token = verify_response.get('gateway_response', {}).get('data', {}).get('token', '')
    
    if not card_token:
        messages.error(request, "Could not extract payment token")
        return redirect('shop:update_payment_method', order_id=order.id)
    
    # Create new payment token
    gateway_response = verify_response.get('gateway_response', {})
    card_data = gateway_response.get('data', {}).get('card', {})
    
    new_payment_token, _ = RecurringPaymentToken.objects.get_or_create(
        user=request.user,
        flutterwave_token=card_token,
        defaults={
            'card_last_four': card_data.get('last_4digits', 'XXXX'),
            'card_brand': card_data.get('type', 'Unknown'),
            'gateway': 'flutterwave',
            'is_authorized': True,
            'authorized_at': timezone.now(),
            'is_active': True,
        }
    )
    
    # Update installment schedule with new token
    installment_schedule.payment_token = new_payment_token
    installment_schedule.save()
    
    # Update order's token as well
    order.flutterwave_token = card_token
    order.save()
    
    messages.success(request, "Payment method updated successfully!")
    return redirect('shop:installment_schedule_detail', order_id=order.id)


# API Endpoints for AJAX
@login_required
def calculate_installment(request):
    """
    AJAX endpoint to calculate monthly payment for different installment options
    """
    if request.method != 'POST':
        return JsonResponse({'error': 'Invalid request'}, status=400)
    
    try:
        amount = Decimal(request.POST.get('amount', 0))
        num_months = int(request.POST.get('months', 1))
        
        if amount <= 0 or num_months < 1:
            return JsonResponse({'error': 'Invalid amount or months'}, status=400)
        
        monthly_payment = amount / Decimal(num_months)
        total_interest_estimate = Decimal('0')  # Add interest calculation if needed
        
        return JsonResponse({
            'monthly_payment': float(monthly_payment),
            'total_amount': float(amount),
            'num_months': num_months,
            'interest': float(total_interest_estimate),
        })
    except (ValueError, TypeError) as e:
        logger.error(f"Error calculating installment: {e}")
        return JsonResponse({'error': 'Invalid input'}, status=400)


@login_required
def payment_status_api(request, order_id):
    """
    AJAX endpoint to get current payment status of an order
    """
    order = get_object_or_404(Order, id=order_id, user=request.user)
    
    if not hasattr(order, 'installment_schedule'):
        return JsonResponse({
            'error': 'No installment schedule',
            'status': order.status,
        })
    
    schedule = order.installment_schedule
    
    return JsonResponse({
        'status': schedule.status,
        'total_installments': schedule.total_installments,
        'paid_installments': schedule.paid_installments,
        'remaining': schedule.remaining_installments,
        'monthly_amount': float(schedule.installment_amount),
        'next_payment_date': schedule.next_payment_date.isoformat(),
    })
