from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse, HttpResponseBadRequest
from django.urls import reverse
from django.contrib import messages
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.conf import settings
from django.utils import timezone
import json

from .models import Event, Registration, PaymentProof
from attendance.models import RegisteredUser as AttendanceRegisteredUser
from .forms import VerifyCodeForm, EventSelectionForm, RegistrationForm, PaymentProofForm
from attendance.models import RegisteredUser as AttendanceRegisteredUser

def registration_home(request):
    """
    Main registration page where users enter their code or choose to register
    """
    form = VerifyCodeForm()
    
    events = Event.objects.filter(is_active=True, end_date__gte=timezone.now()).order_by('start_date')
    
    # If user is coming from payment options and wants to select a different event
    if request.GET.get('action') == 'select_event' and 'registration_code' in request.session:
        registration_code = request.session.get('registration_code')
        # Redirect directly to event selection with their code
        event_form = EventSelectionForm()
        
        # Clear any stale messages to prevent duplicates
        storage = messages.get_messages(request)
        for _ in storage:
            pass
        
        # Get current registration information
        existing_reg = Registration.objects.filter(registration_code=registration_code).first()
        if existing_reg:
            current_event = existing_reg.event.name
            messages.info(request, f'You are currently registered for {current_event}. Select a different event below to update your registration.')
        
        return render(request, 'registration/event_selection.html', {
            'form': event_form,
            'registration_code': registration_code,
        })
    
    return render(request, 'registration/home.html', {
        'form': form,
        'events': events,
    })

def verify_code(request):
    """
    Verify if the registration code exists and direct accordingly
    """
    if request.method == 'POST':
        form = VerifyCodeForm(request.POST)
        if form.is_valid():
            registration_code = form.cleaned_data['registration_code']
            
            # Check if code exists in Registration model
            existing_registrations = Registration.objects.filter(registration_code=registration_code)
            existing_registration = existing_registrations.first()
            
            # Check if code exists in Attendance RegisteredUser model (for backward compatibility)
            existing_attendance_user = AttendanceRegisteredUser.objects.filter(registration_code=registration_code).first()
            
            if existing_registration or existing_attendance_user:
                # Store registration code in session
                request.session['registration_code'] = registration_code
                request.session['is_existing_user'] = True
                
                # Check if user is from attendance module - always check attendance module first
                if existing_attendance_user:
                    # This is an attendance module user, regardless of whether they have a registration
                    request.session['from_attendance_module'] = True
                    request.session['attendance_user_email'] = existing_attendance_user.email
                    request.session['attendance_user_name'] = existing_attendance_user.full_name
                    
                    # If they also have a registration, make sure we mark it as from attendance module
                    if existing_registration:
                        # Update their registration to ensure it's marked as approved
                        existing_registration.status = 'approved'
                        existing_registration.payment_status = 'approved'
                        existing_registration.save()
                else:
                    request.session['from_attendance_module'] = False
                
                # Get user email for further validation
                user_email = existing_registration.email if existing_registration else existing_attendance_user.email
                
                # For attendance module users, skip payment checks and go straight to event selection
                if request.session.get('from_attendance_module', False):
                    # Clear any existing messages
                    storage = messages.get_messages(request)
                    for _ in storage:
                        pass
                    
                    # Populate event selection form
                    event_form = EventSelectionForm()
                    
                    # Welcome message for attendance module users
                    messages.success(request, f'Welcome back, {existing_attendance_user.full_name}! Confirm by selecting the training you will be attending.')
                    
                    return render(request, 'registration/event_selection.html', {
                        'form': event_form,
                        'registration_code': registration_code,
                    })
                
                # For regular users, check for pending payment uploads
                pending_payment_registration = existing_registrations.filter(
                    event__is_paid=True,
                    payment_status='pending'
                ).exclude(
                    payment_proof__isnull=False
                ).first()
                
                if pending_payment_registration:
                    # Clear any existing messages to prevent duplicates
                    storage = messages.get_messages(request)
                    for _ in storage:
                        pass  # Iterate through and clear messages
                    
                    # User has registered for a paid event but not uploaded payment proof
                    event_name = pending_payment_registration.event.name
                    messages.warning(request, f'Please upload your payment proof for {event_name} to complete your registration.')
                    request.session['registration_id'] = str(pending_payment_registration.id)
                    
                    # Show options to either upload payment or change event
                    return render(request, 'registration/payment_options.html', {
                        'registration': pending_payment_registration,
                        'registration_code': registration_code,
                    })
                
                # No pending payments, proceed to event selection
                # Clear any stale messages to prevent duplicates
                storage = messages.get_messages(request)
                for _ in storage:
                    pass
                    
                # Populate event selection form
                event_form = EventSelectionForm()
                
                # Let user know they can update their registration if needed
                if existing_registration:
                    current_event = existing_registration.event.name
                    messages.info(request, f'You are currently registered for {current_event}. You can select a different event below to update your registration.')
                elif existing_attendance_user:  # Add message for attendance module users
                    messages.success(request, f'Welcome back, {existing_attendance_user.full_name}! As an existing ICTAZ member, you can select any training event below without payment requirements.')
                
                return render(request, 'registration/event_selection.html', {
                    'form': event_form,
                    'registration_code': registration_code,
                })
            else:
                # Registration code not found - ask to register as new user
                messages.error(request, 'Registration code not found. Please register as a new user.')
                return redirect('registration_home')
    else:
        form = VerifyCodeForm()
    
    return render(request, 'registration/verify_code.html', {'form': form})


def register_new_user(request, event_id):
    """
    Handle registration for new users
    """
    event = get_object_or_404(Event, pk=event_id)
    
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            # Create registration but don't save to DB yet
            registration = form.save(commit=False)
            registration.event = event
            
            # Check if this email is already registered for ANY event
            existing_registrations = Registration.objects.filter(email=registration.email)
            
            if existing_registrations.exists():
                # User already has a registration
                existing_reg = existing_registrations.first()
                
                if existing_registrations.filter(event=event).exists():
                    # Already registered for this specific event
                    messages.error(request, f'You are already registered for {event.name} with this email address.')
                else:
                    # Registered for a different event
                    existing_event = existing_registrations.first().event
                    messages.error(request, 
                                  f'You are already registered for {existing_event.name}. ' 
                                  f'Please use your registration code {existing_reg.registration_code} to manage your registration.')
                
                return render(request, 'registration/register.html', {
                    'form': form,
                    'event': event,
                })
            
            # Save registration to generate registration code
            registration.save()
            
            # Store registration ID in session for next steps
            request.session['registration_id'] = str(registration.id)
            
            if event.is_paid:
                # Redirect to payment upload
                return redirect('upload_payment', registration_id=registration.id)
            else:
                # If the event is free, mark as approved and send confirmation email
                registration.status = 'approved'
                registration.save()
                
                # Send confirmation email
                send_registration_email(registration)
                
                # Redirect to success page
                messages.success(request, 'Registration successful!')
                return redirect('registration_success')
    else:
        form = RegistrationForm()
    
    return render(request, 'registration/register.html', {
        'form': form,
        'event': event,
    })


def upload_payment(request, registration_id):
    """
    Handle payment proof upload
    """
    registration = get_object_or_404(Registration, pk=registration_id)
    
    # Security check - ensure registration belongs to the current session
    if 'registration_id' not in request.session or request.session['registration_id'] != registration_id:
        messages.error(request, 'Invalid session. Please start registration again.')
        return redirect('registration_home')
    
    if request.method == 'POST':
        form = PaymentProofForm(request.POST, request.FILES)
        if form.is_valid():
            # Check if a payment proof already exists for this registration
            try:
                existing_proof = PaymentProof.objects.get(registration=registration)
                # Delete the existing payment proof
                existing_proof.delete()
            except PaymentProof.DoesNotExist:
                # No existing payment proof, continue as normal
                pass
                
            # Create new payment proof
            payment_proof = form.save(commit=False)
            payment_proof.registration = registration
            payment_proof.save()
            
            # Update registration status
            registration.payment_status = 'pending'
            registration.save()
            
            # Send confirmation email
            send_registration_email(registration, payment_pending=True)
            
            messages.success(request, 'Your payment proof has been updated and submitted. An administrator will review your payment.')
            return redirect('registration_success')
    else:
        form = PaymentProofForm()
    
    return render(request, 'registration/upload_payment.html', {
        'form': form,
        'registration': registration,
        'event': registration.event,
        'bank_details': get_bank_details(),
    })


def process_event_selection(request):
    """
    Handle event selection for existing users
    """
    if request.method != 'POST' or 'registration_code' not in request.session:
        return redirect('registration_home')
    
    form = EventSelectionForm(request.POST)
    registration_code = request.session.get('registration_code')
    
    # Ensure we correctly identify attendance module users
    # This is critical for bypassing payment proof requirements
    from_attendance_module = request.session.get('from_attendance_module', False)
    
    # If this is an attendance module user, ensure we have their info
    if from_attendance_module and ('attendance_user_email' not in request.session or 'attendance_user_name' not in request.session):
        # Try to get the attendance user info from the database
        attendance_user = AttendanceRegisteredUser.objects.filter(registration_code=registration_code).first()
        if attendance_user:
            request.session['attendance_user_email'] = attendance_user.email
            request.session['attendance_user_name'] = attendance_user.full_name
        else:
            # If we can't find the attendance user, reset the flag
            from_attendance_module = False
            request.session['from_attendance_module'] = False
    
    if form.is_valid():
        selected_event = form.cleaned_data['event']
        
        # Check if user is from attendance module
        if from_attendance_module:
            # Get user details from session
            user_email = request.session.get('attendance_user_email')
            user_fullname = request.session.get('attendance_user_name')
            
            # For attendance users, check if they already have a registration in our system
            existing_registration = Registration.objects.filter(email=user_email).first()
            
            # If no registration exists yet for this attendance user, create one
            if not existing_registration:
                # Create a new registration record for this attendance user
                new_registration = Registration(
                    full_name=user_fullname,
                    email=user_email,
                    registration_code=registration_code,
                    status='approved',  # Automatically approved
                    event=selected_event
                )
                
                # Set payment status to approved for attendance users
                if selected_event.is_paid:
                    new_registration.payment_status = 'approved'
                else:
                    new_registration.payment_status = 'not_required'
                    
                # Save the new registration
                new_registration.save()
                
                # Store registration ID in session
                request.session['registration_id'] = str(new_registration.id)
                
                # Redirect to success page
                messages.success(request, f'You have been successfully registered for {selected_event.name}.')
                return redirect('registration_success')
        else:
            # Get the existing user details from the registration code
            existing_registration = Registration.objects.filter(registration_code=registration_code).first()
            
            if not existing_registration:
                messages.error(request, 'Registration code no longer valid. Please register as a new user.')
                return redirect('registration_home')
                
            # Get user details
            user_email = existing_registration.email
            user_fullname = existing_registration.full_name
        
        # Get all registrations for this user by email
        all_user_registrations = Registration.objects.filter(email=user_email)
        
        # Check if user is already registered for THIS event
        if all_user_registrations.filter(event=selected_event).exists():
            # Already registered for this specific event
            existing_event_reg = all_user_registrations.get(event=selected_event)
            
            # For attendance module users, ensure their registration is approved
            if from_attendance_module:
                # Update the registration status to approved
                existing_event_reg.status = 'approved'
                existing_event_reg.payment_status = 'approved'
                existing_event_reg.save()
                
                # Store registration ID in session for success page
                request.session['registration_id'] = str(existing_event_reg.id)
                
                # Inform the user they're already registered
                messages.info(request, f'You are already registered for {selected_event.name}.')
                return redirect('registration_success')
            
            # For regular users, check if payment is needed but not provided yet
            elif selected_event.is_paid:
                # Check if payment proof exists
                try:
                    payment_proof = existing_event_reg.payment_proof
                    has_payment_proof = True
                except Exception:
                    has_payment_proof = False
                    
                if not has_payment_proof:
                    # No payment proof uploaded yet
                    messages.warning(request, f'You need to upload payment proof for {selected_event.name}.')
                    request.session['registration_id'] = str(existing_event_reg.id)
                    return redirect('upload_payment', registration_id=existing_event_reg.id)
                elif has_payment_proof and existing_event_reg.payment_status == 'pending':
                    # Payment proof uploaded but still pending approval
                    messages.info(request, f'Your payment proof for {selected_event.name} has been uploaded and is awaiting approval.')
                    # Ask if they want to update their payment proof
                    request.session['registration_id'] = str(existing_event_reg.id)
                    return render(request, 'registration/update_payment_proof.html', {
                        'registration': existing_event_reg,
                        'event': selected_event,
                        'has_existing_proof': True,
                        'bank_details': get_bank_details()
                    })
            # For attendance module users, ensure payment status is approved
            elif selected_event.is_paid and from_attendance_module:
                existing_event_reg.payment_status = 'approved'
                existing_event_reg.status = 'approved'  # Ensure registration status is approved
                existing_event_reg.save()
                
                # Store registration ID in session for success page
                request.session['registration_id'] = str(existing_event_reg.id)
            
            # Already registered for this event with complete info
            messages.info(request, f'You are already registered for {selected_event.name}.')
            
            # For attendance module users, redirect to success page instead of home
            if from_attendance_module:
                return redirect('registration_success')
            else:
                return redirect('registration_home')
            
        # Check if user is registered for ANY OTHER event
        other_events = all_user_registrations.exclude(event=selected_event)
        
        if other_events.exists():
            # User has an existing registration for another event
            other_event = other_events.first()
            
            # Ask if they want to update their registration
            if request.POST.get('confirm_update') == 'yes':
                # Update the existing registration to the new event
                other_event.event = selected_event
                
                # Reset payment status if new event is paid
                if selected_event.is_paid and not from_attendance_module:
                    if other_event.event.is_paid:
                        # Both old and new events are paid, keep payment status
                        pass
                    else:
                        # New event is paid, old wasn't - set to pending
                        other_event.payment_status = 'pending'
                elif selected_event.is_paid and from_attendance_module:
                    # Attendance module users get automatic approval
                    other_event.payment_status = 'approved'
                    other_event.status = 'approved'
                else:
                    # New event is free - set to not required and approved
                    other_event.payment_status = 'not_required'
                    other_event.status = 'approved'
                    
                other_event.save()
                
                messages.success(request, f'Your registration has been updated to {selected_event.name}.')
                
                # If the new event is paid and requires payment proof
                # Check if the user is from attendance module (they don't need payment)
                if selected_event.is_paid and not from_attendance_module:
                    # Check if payment proof already exists
                    try:
                        payment_proof = other_event.payment_proof
                        has_payment_proof = True
                    except Exception:
                        has_payment_proof = False
                        
                    if not has_payment_proof:
                        # Need to upload payment proof for new event
                        messages.warning(request, f'Please upload payment proof for {selected_event.name}.')
                        request.session['registration_id'] = str(other_event.id)
                        return redirect('upload_payment', registration_id=other_event.id)
                    elif has_payment_proof and other_event.payment_status == 'pending':
                        # Payment proof uploaded but still pending approval
                        # Show the update payment proof page instead of asking for a new upload
                        request.session['registration_id'] = str(other_event.id)
                        return render(request, 'registration/update_payment_proof.html', {
                            'registration': other_event,
                            'event': selected_event,
                            'has_existing_proof': True,
                            'bank_details': get_bank_details()
                        })
                elif selected_event.is_paid and from_attendance_module:
                    # Attendance module users get automatic payment approval
                    other_event.payment_status = 'approved'
                    other_event.status = 'approved'
                
                # Save the updated registration
                other_event.save()
                
                # Redirect to success page with update flag
                request.session['registration_id'] = str(other_event.id)
                request.session['is_registration_update'] = True
                return redirect('registration_success')
            else:
                # Show confirmation form for updating registration
                other_event_name = other_event.event.name
                return render(request, 'registration/confirm_update.html', {
                    'current_event': other_event_name,
                    'new_event': selected_event.name,
                    'registration_code': registration_code,
                    'event_id': selected_event.id
                })
        
        # Create a new registration for the user
        try:
            # Try to reuse the existing registration code
            new_registration = Registration(
                full_name=user_fullname,
                email=user_email,
                event=selected_event,
                registration_code=registration_code,  # Use the same registration code
                status='approved'  # Always approved for existing users
            )
            
            # Set payment status
            if selected_event.is_paid and not from_attendance_module:
                # Regular users need to provide payment
                new_registration.payment_status = 'pending'
            elif selected_event.is_paid and from_attendance_module:
                # Attendance module users are automatically approved for payment
                new_registration.payment_status = 'approved'
                new_registration.status = 'approved'  # Ensure registration status is approved
                
            new_registration.save()
            
        except Exception:
            # If reusing code fails, create with a new code
            new_registration = Registration(
                full_name=user_fullname,
                email=user_email,
                event=selected_event,
                status='approved'
            )
            
            if selected_event.is_paid and from_attendance_module:
                # Attendance module users are automatically approved
                new_registration.payment_status = 'approved'
            elif selected_event.is_paid:
                # Regular users need to provide payment
                new_registration.payment_status = 'pending'
                
            new_registration.save()
        
        # Store registration ID in session
        request.session['registration_id'] = str(new_registration.id)
        
        # Send confirmation email
        send_registration_email(new_registration)
        
        messages.success(request, f'Successfully registered for {selected_event.name}!')
        return redirect('registration_success')
    else:
        # Form validation failed
        return render(request, 'registration/event_selection.html', {
            'form': form,
            'registration_code': registration_code,
        })


def registration_success(request):
    """
    Display success page after registration
    """
    registration_id = request.session.get('registration_id')
    is_update = request.session.get('is_registration_update', False)
    
    if registration_id:
        registration = Registration.objects.filter(pk=registration_id).first()
        
        # Add a custom success message for updates vs new registrations
        if is_update and not any(m.tags == 'success' for m in messages.get_messages(request)):
            messages.success(request, f'Your registration has been updated successfully.')
        elif not is_update and not any(m.tags == 'success' for m in messages.get_messages(request)):
            messages.success(request, f'Registration successful! Your registration code is {registration.registration_code}.')
        
        # Clear session data
        if 'registration_id' in request.session:
            del request.session['registration_id']
        if 'registration_code' in request.session:
            del request.session['registration_code']
        if 'is_existing_user' in request.session:
            del request.session['is_existing_user']
        if 'is_registration_update' in request.session:
            del request.session['is_registration_update']
    else:
        registration = None
    
    return render(request, 'registration/success.html', {
        'registration': registration,
    })

def event_list_api(request):
    """
    API endpoint to get the list of active events
    """
    events = Event.objects.filter(
        is_active=True, 
        end_date__gte=timezone.now()
    ).values('id', 'name', 'event_type__name', 'start_date', 'end_date', 'location', 'is_paid', 'amount')
    
    return JsonResponse(list(events), safe=False)


# Helper functions
def send_registration_email(registration, payment_pending=False):
    """
    Send registration confirmation email
    """
    subject = f"ICTAZ Event Registration: {registration.event.name}"
    
    context = {
        'registration': registration,
        'event': registration.event,
        'payment_pending': payment_pending,
    }
    
    try:
        # Render email content from template
        email_html = render_to_string('registration/email/confirmation.html', context)
        email_text = render_to_string('registration/email/confirmation.txt', context)
        
        # Send email
        result = send_mail(
            subject=subject,
            message=email_text,
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[registration.email],
            html_message=email_html,
            fail_silently=False,
        )
        print(f"Email sent to {registration.email} - Result: {result}")
        return True
    except Exception as e:
        print(f"Error sending email to {registration.email}: {str(e)}")
        return False


def get_bank_details():
    """
    Return bank details for payment
    """
    return {
        'bank_name': 'ABSA BANK ZAMBIA PLC',
        'branch': 'CHINGOLA BRANCH',
        'account_number': '032268749',
        'beneficiary': 'Information And Communications Technology Association of Zambia',
        'swift_code': 'BARCZMLX',
        'sort_code': '020303',
    }
