from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.contrib import messages
from django.contrib.auth import login, views as auth_views
from django.utils import timezone
from django.db.models import Case, When, Value, BooleanField
from datetime import timedelta
from django.http import JsonResponse, HttpResponse
from django.urls import reverse
from django.utils import timezone
from django.db.models import Q
from django.db import models
import csv
from .models import (
    Event, 
    Speaker, 
    Agenda, 
    CallForProposal, 
    Gallery, 
    Registration, 
    UserProfile,
    Role,
    Proposal,
    Publication,
    SessionType,
    PublicationType,
    CarouselImage,
    Sponsor,
    SectionImage,
)
from .forms import (
    UserRegistrationForm,
    UserProfileForm,
    ProposalForm,
    SpeakerForm
)
from .forms.password_reset import CustomPasswordResetForm

# Home View
def index(request):
    """Home page view."""
    now = timezone.now()
    
    # Get active carousel images
    carousel_images = CarouselImage.objects.filter(is_active=True).order_by('order')
    
    # Get section images
    try:
        join_community_image = SectionImage.objects.get(section='join_community', is_active=True)
    except SectionImage.DoesNotExist:
        join_community_image = None
    
    # Get sponsors and group them for carousel (3 per slide)
    sponsors = list(Sponsor.objects.filter(is_active=True).order_by('order'))
    sponsor_groups = [sponsors[i:i + 3] for i in range(0, len(sponsors), 3)]
    
    # Get latest events (only upcoming events)
    # Based on CFP validation pattern, we only show upcoming events
    # The Event model automatically updates status based on date_time and end_time
    latest_events = Event.objects.filter(
        status='upcoming',  # Must be upcoming (not ongoing or archived)
        date_time__gte=now  # Double-check future date for consistency with CFP validation
    ).order_by('date_time')[:6]
    
    # Get latest announcement (only upcoming events)
    latest_announcement = Event.objects.filter(
        status='upcoming',  # Must be upcoming (not ongoing or archived)
        date_time__gte=now  # Double-check future date for consistency with CFP validation
    ).order_by('date_time').first()
    
    context = {
        'latest_events': latest_events,
        'latest_announcement': latest_announcement,
        'carousel_images': carousel_images,
        'sponsor_groups': sponsor_groups,
        'join_community_image': join_community_image,
        'now': now
    }
    
    return render(request, 'events/index.html', context)

# Create your views here.
def register(request):
    """Handle user registration"""
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)
        if form.is_valid():
            user = form.save()
            # Get or create associated profile with default attendee role
            role = Role.objects.get_or_create(name='attendee')[0]  # Using ROLE_CHOICES from Role model
            UserProfile.objects.get_or_create(
                user=user,
                defaults={'role': role}
            )
            login(request, user)
            
            # Send welcome email
            try:
                from events.utils.email_utils import send_welcome_email
                send_welcome_email(user, request)
            except Exception as e:
                # Log the error but don't prevent registration
                print(f'Error sending welcome email: {e}')
                
            messages.success(request, 'Registration successful! Welcome to Bloggers Event Management System. Please check your email for more information.')
            return redirect('events:my_profile')
    else:
        form = UserRegistrationForm()
    return render(request, 'registration/register.html', {'form': form})

@login_required
def user_list(request):
    """Display list of users with role management."""
    if not request.user.is_staff and not request.user.is_superuser:
        messages.error(request, 'You do not have permission to view this page.')
        return redirect('events:index')
    
    users = User.objects.all().order_by('-date_joined')
    
    # Add registration counts and latest event status for each user
    now = timezone.now()
    two_hours_ago = now - timedelta(hours=2)
    
    for user in users:
        registrations = Registration.objects.filter(user=user).select_related('event')
        user.registration_count = registrations.count()
        
        # Get latest event registration if any
        latest_reg = registrations.order_by('-event__date_time').first()
        if latest_reg:
            event = latest_reg.event
            if event.date_time > now:
                user.latest_event_status = 'Upcoming'
                user.latest_event_color = 'info'
            elif event.date_time <= now and event.date_time > two_hours_ago:
                user.latest_event_status = 'Ongoing'
                user.latest_event_color = 'success'
            else:
                user.latest_event_status = 'Archived'
                user.latest_event_color = 'secondary'
            user.latest_event = event
        else:
            user.latest_event = None
    
    context = {
        'users': users,
    }
    return render(request, 'events/user_list.html', context)

@login_required
@user_passes_test(lambda u: u.is_superuser)
def make_admin(request, username):
    """Make a user a superuser/admin."""
    user = get_object_or_404(User, username=username)
    user.is_superuser = True
    user.is_staff = True
    user.save()
    
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'status': 'success',
            'role': 'Superuser',
            'message': f'{user.username} is now a superuser'
        })
    
    messages.success(request, f'{user.username} is now a superuser')
    return redirect('events:user_list')

@login_required
@user_passes_test(lambda u: u.is_superuser)
def remove_admin(request, username):
    """Remove superuser/admin status from a user."""
    user = get_object_or_404(User, username=username)
    if user == request.user:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'error',
                'message': 'You cannot remove your own admin privileges'
            })
        messages.error(request, 'You cannot remove your own admin privileges')
        return redirect('events:user_list')
    
    user.is_superuser = False
    user.save()
    
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'status': 'success',
            'role': 'Staff' if user.is_staff else 'Attendee',
            'message': f'Admin privileges removed from {user.username}'
        })
    
    messages.success(request, f'Admin privileges removed from {user.username}')
    return redirect('events:user_list')

@login_required
@user_passes_test(lambda u: u.is_staff or u.is_superuser)
def make_staff(request, username):
    """Make a user a staff member."""
    user = get_object_or_404(User, username=username)
    user.is_staff = True
    user.save()
    
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'status': 'success',
            'role': 'Staff',
            'message': f'{user.username} is now a staff member'
        })
    
    messages.success(request, f'{user.username} is now a staff member')
    return redirect('events:user_list')

@login_required
@user_passes_test(lambda u: u.is_staff or u.is_superuser)
def remove_staff(request, username):
    """Remove staff status from a user."""
    user = get_object_or_404(User, username=username)
    if user.is_superuser:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'error',
                'message': 'Cannot remove staff status from superusers'
            })
        messages.error(request, 'Cannot remove staff status from superusers')
        return redirect('events:user_list')
    
    if user == request.user:
        if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'status': 'error',
                'message': 'You cannot remove your own staff privileges'
            })
        messages.error(request, 'You cannot remove your own staff privileges')
        return redirect('events:user_list')
    
    user.is_staff = False
    user.save()
    
    if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
        return JsonResponse({
            'status': 'success',
            'role': 'Attendee',
            'message': f'Staff privileges removed from {user.username}'
        })
    
    messages.success(request, f'Staff privileges removed from {user.username}')
    return redirect('events:user_list')

@login_required
@user_passes_test(lambda u: u.is_staff or u.is_superuser)
def export_users_csv(request):
    """Export user list to CSV."""
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="users.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Username', 'Email', 'First Name', 'Last Name', 'Role', 'Status', 'Date Joined', 'Last Login'])
    
    users = User.objects.all().order_by('-date_joined')
    
    for user in users:
        role = 'Superuser' if user.is_superuser else 'Staff' if user.is_staff else 'Attendee'
        writer.writerow([
            user.username,
            user.email,
            user.first_name,
            user.last_name,
            role,
            'Active' if user.is_active else 'Inactive',
            user.date_joined.strftime('%Y-%m-%d %H:%M:%S'),
            user.last_login.strftime('%Y-%m-%d %H:%M:%S') if user.last_login else 'Never'
        ])
    
    return response

@login_required
@user_passes_test(lambda u: u.is_staff or u.is_superuser)
def export_event_registrations_csv(request, event_id):
    """Export event registrations to CSV."""
    event = get_object_or_404(Event, id=event_id)
    
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = f'attachment; filename="{event.title}_registrations.csv"'
    
    writer = csv.writer(response)
    writer.writerow(['Username', 'Email', 'Full Name', 'Organization', 'Phone', 'Registration Date', 'Status'])
    
    registrations = Registration.objects.filter(event=event).select_related('user', 'user__userprofile')
    
    for registration in registrations:
        writer.writerow([
            registration.user.username,
            registration.user.email,
            registration.user.get_full_name() or registration.user.username,
            registration.user.userprofile.organization,
            registration.user.userprofile.phone_number,
            registration.registration_date.strftime('%Y-%m-%d %H:%M:%S'),
            registration.get_status_display()
        ])
    
    return response

@login_required
def user_profile(request, username=None):
    """Display user profile. Admins can view other users' profiles."""
    if username:
        if not request.user.is_staff and not request.user.is_superuser and request.user.username != username:
            messages.error(request, 'You do not have permission to view this profile.')
            return redirect('events:my_profile')
        profile_user = get_object_or_404(User, username=username)
    else:
        profile_user = request.user
    
    # Get user's registrations with event status
    now = timezone.now()
    two_hours_ago = now - timedelta(hours=2)
    
    registrations = Registration.objects.filter(user=profile_user).select_related('event')
    
    # Add status to each event
    for registration in registrations:
        event = registration.event
        if event.date_time > now:
            event.status = 'Upcoming'
            event.status_color = 'info'
        elif event.date_time <= now and event.date_time > two_hours_ago:
            event.status = 'Ongoing'
            event.status_color = 'success'
        else:
            event.status = 'Archived'
            event.status_color = 'secondary'
    
    context = {
        'profile_user': profile_user,
        'registrations': registrations,
    }
    return render(request, 'events/user_profile.html', context)

def publications_view(request):
    """Display all public documents and materials"""
    # Get publications from archived events
    publications = Publication.objects.filter(
        is_public=True,
        file__isnull=False  # Has file uploaded
    ).exclude(
        file=''  # Exclude empty strings
    ).select_related('author','publication_type').order_by('-published_at')

    # Format all publications
    all_publications = []
    
    # Add publications
    for publication in publications:
        all_publications.append({
            'id': f'publication_{publication.id}',
            'title': publication.title,
            'abstract': publication.abstract,
            'author': publication.author,
            'date': publication.published_at,
            'type': publication.publication_type.name,
            'files': [{
                'url': publication.file.url,
                'type': publication.publication_type.name,
                'icon': publication.publication_type.icon
            }]
        })

    # Sort all publications by date (newest first)
    all_publications.sort(key=lambda x: x['date'], reverse=True)

    # Get all publication types for filtering
    publication_types = PublicationType.objects.all().order_by('name')
    
    return render(request, 'events/publications.html', {
        'publications': all_publications,
        'publication_types': publication_types
    })

# Event Views
def event_list(request):
    """Display list of events with filtering options"""
    status = request.GET.get('status', 'all')
    now = timezone.now()

    if status == 'upcoming':
        # Get upcoming events using the status field
        events = Event.objects.filter(status='upcoming').order_by('date_time')
        
        context = {
            'upcoming_events': events,
            'ongoing_events': Event.objects.none(),
            'archived_events': Event.objects.none(),
            'current_status': status
        }
    elif status == 'ongoing':
        # Get ongoing events using the status field
        events = Event.objects.filter(status='ongoing').order_by('date_time')
        
        context = {
            'upcoming_events': Event.objects.none(),
            'ongoing_events': events,
            'archived_events': Event.objects.none(),
            'current_status': status
        }
    elif status == 'archived':
        # Get archived events using the status field
        events = Event.objects.filter(status='archived').order_by('-date_time')
        
        context = {
            'upcoming_events': Event.objects.none(),
            'ongoing_events': Event.objects.none(),
            'archived_events': events,
            'current_status': status
        }
    else:
        # Show all events, properly categorized using the status field
        upcoming = Event.objects.filter(status='upcoming').order_by('date_time')
        ongoing = Event.objects.filter(status='ongoing').order_by('date_time')
        archived = Event.objects.filter(status='archived').order_by('-date_time')[:5]
        
        context = {
            'upcoming_events': upcoming,
            'ongoing_events': ongoing,
            'archived_events': archived,
            'show_all_archived': True,
            'current_status': status,
            'now': now,  # Add current time for event status checks
        }
    
    return render(request, 'events/event_list.html', context)

def event_detail(request, event_id):
    """Event detail view."""
    event = get_object_or_404(Event, pk=event_id)
    now = timezone.now()

    # Get event speakers
    speakers = event.speakers.all()
    
    # Get event sponsors and group them for carousel (3 per slide)
    sponsors = list(event.sponsors.filter(is_active=True).order_by('order'))
    sponsor_groups = [sponsors[i:i + 3] for i in range(0, len(sponsors), 3)]

    # Get CFPs if any
    cfps = event.cfps.all()
    
    # Get active CFPs for the event
    active_cfps = cfps.filter(status='open', submission_deadline__gt=now)
    
    # Get registrations if user is authenticated
    user_registration = None
    if request.user.is_authenticated:
        user_registration = Registration.objects.filter(
            event=event,
            user=request.user
        ).first()

    # Get agenda items with speakers
    agenda_items = event.agendas.all().order_by('session_time').prefetch_related('speakers')

    # Get gallery images for this event
    gallery_items = event.gallery.all()  # Using the related_name from Gallery model

    context = {
        'event': event,
        'stream_status': 'live' if event.is_ongoing else 'recorded' if event.is_archived else 'scheduled',
        'speakers': speakers,
        'sponsor_groups': sponsor_groups,
        'cfps': cfps,
        'active_cfps': active_cfps,
        'agenda_items': agenda_items,
        'user_registration': user_registration,
        'gallery_items': gallery_items,  # Add gallery items to context
        'now': now,
    }

    return render(request, 'events/event_detail.html', context)

def speaker_detail(request, speaker_id):
    """Display detailed information about a specific speaker and their events"""
    speaker = get_object_or_404(Speaker, id=speaker_id)
    now = timezone.now()
    
    # Get all events associated with the speaker
    events = speaker.events.all()
    
    # Filter events using model properties
    upcoming_events = [event for event in events if event.is_upcoming]
    ongoing_events = [event for event in events if event.is_ongoing]
    past_events = [event for event in events if event.is_archived]
    
    # Combine upcoming and ongoing events for active events section
    active_events = sorted(upcoming_events + ongoing_events, key=lambda x: x.date_time)
    # Sort past events in reverse chronological order
    past_events.sort(key=lambda x: x.date_time, reverse=True)
    
    return render(request, 'events/speaker_detail.html', {
        'speaker': speaker,
        'upcoming_events': active_events,
        'past_events': past_events,
        'now': now,
    })

# Call for Proposals Views
def cfp_list(request):
    """Display list of open call for proposals and user's existing submissions"""
    now = timezone.now()
    
    # Get all open CFPs with their associated events
    open_cfps = CallForProposal.objects.filter(
        status='open',
        submission_deadline__gte=now,
        event__date_time__gt=now
    ).select_related('event').order_by('submission_deadline')
    
    # Get user's existing submissions if authenticated
    user_proposals = []
    if request.user.is_authenticated:
        user_proposals = Proposal.objects.filter(
            submitter=request.user
        ).select_related(
            'cfp',
            'cfp__event'
        ).order_by('-submitted_at')
        
        # Add event status flags to each proposal using the Event model's properties
        for proposal in user_proposals:
            event = proposal.cfp.event
            proposal.is_archived = event.is_archived
            proposal.is_ongoing = event.is_ongoing
            proposal.is_upcoming = event.is_upcoming
    
    return render(request, 'events/cfp_list.html', {
        'cfps': open_cfps,
        'user_proposals': user_proposals,
        'now': now  # Add current time for event status checks
    })

def cfp_detail(request, cfp_id):
    """Display detailed information about a specific Call for Proposal"""
    cfp = get_object_or_404(CallForProposal, id=cfp_id)
    now = timezone.now()
    
    # Use the Event model's properties for status checks
    event = cfp.event
    is_archived = event.is_archived
    is_ongoing = event.is_ongoing
    is_upcoming = event.is_upcoming
    
    # Check if user can submit
    can_submit = (
        cfp.status == 'open' and 
        cfp.submission_deadline > now and
        is_upcoming  # Only allow submissions for upcoming events
    )
    
    # Get proposals for this CFP
    proposals = []
    if request.user.is_authenticated:
        if request.user.is_staff:
            # Staff can see all proposals
            proposals = Proposal.objects.filter(cfp=cfp).select_related('submitter')
        else:
            # Regular users can only see their own proposals
            proposals = Proposal.objects.filter(cfp=cfp, submitter=request.user)
    
    context = {
        'cfp': cfp,
        'proposals': proposals,
        'can_submit': can_submit,
        'now': now,  # Add current time for event status checks
        'is_archived': is_archived,
        'is_ongoing': is_ongoing,
        'is_upcoming': is_upcoming
    }
    return render(request, 'events/cfp_detail.html', context)

@login_required
def submit_proposal(request, cfp_id):
    """Handle submission and editing of proposals with file uploads"""
    cfp = get_object_or_404(CallForProposal.objects.select_related('event'), id=cfp_id)
    proposal = None
    
    # Check if this is an edit of an existing proposal
    edit_id = request.GET.get('edit')
    existing_proposal = None
    
    if edit_id:
        # If editing, get the specific proposal
        try:
            existing_proposal = Proposal.objects.select_related('cfp', 'submitter').get(
                id=edit_id,
                submitter=request.user,
                cfp=cfp  # Ensure proposal belongs to this CFP
            )
        except Proposal.DoesNotExist:
            messages.error(request, 'Invalid proposal edit request.')
            return redirect('events:cfp_list')
    
    # Check submission permissions
    now = timezone.now()
    event = cfp.event
    
    if existing_proposal:
        if existing_proposal.submitter != request.user:
            error_msg = 'You can only edit your own proposals.'
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'status': 'error',
                    'message': error_msg
                })
            messages.error(request, error_msg)
            return redirect('events:cfp_list')
        
        # Check event status for editing
        if event.is_archived:
            error_msg = 'Cannot edit proposals for archived events.'
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'status': 'error',
                    'message': error_msg
                })
            messages.error(request, error_msg)
            return redirect('events:cfp_list')
        elif event.is_ongoing:
            error_msg = 'Cannot edit proposals for ongoing events.'
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'status': 'error',
                    'message': error_msg
                })
            messages.error(request, error_msg)
            return redirect('events:cfp_list')
    else:
        # For new submissions, check event status and CFP deadline
        if not event.is_upcoming:
            error_msg = 'Cannot submit proposals for {} events.'.format(
                'archived' if event.is_archived else 'ongoing'
            )
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'status': 'error',
                    'message': error_msg
                })
            messages.error(request, error_msg)
            return redirect('events:cfp_list')
        
        if cfp.status != 'open':
            error_msg = 'This Call for Proposals is no longer accepting submissions.'
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'status': 'error',
                    'message': error_msg
                }, status=400)
            messages.error(request, error_msg)
            return redirect('events:cfp_list')
    
    if request.method == 'POST':
        # Get the title from POST data
        title = request.POST.get('title', '').strip()
        
        # Check for duplicate title if not editing
        if not edit_id:
            # Check for any proposal with same title by this user for this CFP
            existing_proposals = Proposal.objects.filter(
                cfp=cfp,
                submitter=request.user,
                title__iexact=title  # Case-insensitive title match
            )
            
            if existing_proposals.exists():
                error_msg = f'A proposal with the title "{title}" already exists.'
                if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                    return JsonResponse({
                        'status': 'error',
                        'message': error_msg
                    }, status=400)
                messages.error(request, error_msg)
                return redirect('events:cfp_list')
                
            # Check event status based on timing rules
            if not cfp.event.is_upcoming:
                error_msg = 'Cannot submit proposals for {} events.'.format(
                    'archived' if cfp.event.is_archived else 'ongoing'
                )
                if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                    return JsonResponse({
                        'status': 'error',
                        'message': error_msg
                    })
                messages.error(request, error_msg)
                return redirect('events:cfp_list')

        # Use existing proposal for edit, or None for new
        instance = existing_proposal if edit_id else None
        form = ProposalForm(request.POST, request.FILES, instance=instance)
        
        if form.is_valid():
            # Process form data manually since we're not using a Django form
            organisation = request.POST.get('organisation', '').strip()
            contact_number = request.POST.get('contact_number', '').strip()
            abstract = request.POST.get('abstract', '').strip()
            sub_theme = request.POST.get('sub_theme', '').strip()
            learning_objectives = request.POST.get('learning_objectives', '').strip()
            sponsorship = request.POST.get('sponsorship', '').strip()
            additional_notes = request.POST.get('additional_notes', '').strip()
            
            # Get session type
            try:
                session_type_id = int(request.POST.get('session_type', 0))
                session_type = SessionType.objects.get(id=session_type_id)
            except (ValueError, SessionType.DoesNotExist):
                error_msg = 'Please select a valid session type.'
                if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                    return JsonResponse({
                        'status': 'error',
                        'message': error_msg
                    }, status=400)
                messages.error(request, error_msg)
                return redirect('events:submit_proposal', cfp_id=cfp.id)
            
            # Create or update proposal
            if existing_proposal:
                proposal = existing_proposal
            else:
                proposal = Proposal(cfp=cfp, submitter=request.user)
            
            # Set all fields
            proposal.title = title
            proposal.organisation = organisation
            proposal.contact_number = contact_number
            proposal.abstract = abstract
            proposal.sub_theme = sub_theme
            proposal.session_type = session_type
            proposal.learning_objectives = learning_objectives
            proposal.sponsorship = sponsorship
            proposal.additional_notes = additional_notes
            proposal.submitted_at = timezone.now()
            
            # Set status and ensure proper publication state
            if not edit_id:
                proposal.status = 'submitted'
                # No publication-related code needed
            
            # Validate and check for duplicate files
            def validate_file(file, allowed_extensions, max_size, file_type):
                if not file:
                    return None
                
                # Check file extension
                if not any(file.name.lower().endswith(ext) for ext in allowed_extensions):
                    return {
                        'type': 'format',
                        'message': f'{file_type} must be in {" or ".join(allowed_extensions)} format.'
                    }
                
                # Check file size
                if file.size > max_size:
                    return {
                        'type': 'size',
                        'message': f'{file_type} file size must be under {max_size // (1024 * 1024)}MB.'
                    }
                
                # Check for duplicate file content
                import hashlib
                
                # Generate hash of file content
                file_hash = hashlib.md5()
                for chunk in file.chunks():
                    file_hash.update(chunk)
                content_hash = file_hash.hexdigest()
                
                # Reset file pointer for later use
                file.seek(0)
                
                # Check if a file with same content exists
                from events.models import Proposal
                existing = Proposal.objects.filter(
                    supporting_document__contains=file.name,
                    cfp__event=cfp.event
                ).exclude(id=proposal.id if instance else None).first()
                
                if existing:
                    return {
                        'type': 'duplicate',
                        'message': f'This {file_type.lower()} appears to be already used in another proposal for this event.',
                        'warning': True  # This is a warning, not a blocking error
                    }
                
                return None
            
            errors = []
            warnings = []
            
            # Check supporting document only (presentation_slides removed)
            doc = request.FILES.get('supporting_document')
            if doc:
                result = validate_file(doc, ('.pdf',), 5 * 1024 * 1024, 'Supporting document')
                if result:
                    if result.get('warning'):
                        warnings.append(result['message'])
                    else:
                        errors.append(result['message'])
                # Assign the file to the proposal object
                proposal.supporting_document = doc
            
            # If there are blocking errors, show them
            if errors:
                error_msg = 'Please fix the following errors:'
                if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                    return JsonResponse({
                        'status': 'error',
                        'message': error_msg,
                        'errors': errors,
                        'warnings': warnings
                    })
                for error in errors:
                    messages.error(request, error)
                return render(request, 'events/submit_proposal.html', {
                    'form': form,
                    'cfp': cfp,
                    'proposal': existing_proposal,
                    'errors': errors,
                    'warnings': warnings,
                    'now': now  # Add current time for event status checks
                })
            
            # Show warnings but allow submission
            for warning in warnings:
                messages.warning(request, warning)
            
            # All validations passed, proceed with saving
            proposal.save()
            
            # Send confirmation email for new submissions (not updates)
            if not existing_proposal:
                try:
                    from events.utils.email_utils import send_proposal_confirmation_email
                    send_proposal_confirmation_email(proposal)
                except Exception as e:
                    # Log the error but don't prevent submission
                    print(f'Error sending proposal confirmation email: {e}')
            
            action = 'updated' if existing_proposal else 'submitted'
            success_msg = f'Your proposal has been {action} successfully!'
            if not existing_proposal:
                success_msg += ' A confirmation email has been sent to your email address.'
            
            # Add any warnings to the success message
            if warnings:
                success_msg += '\n\nNote:\n' + '\n'.join('- ' + w for w in warnings)
            
            response_data = {
                'status': 'success',
                'message': success_msg,
                'redirect_url': reverse('events:cfp_list')
            }
            if warnings:
                response_data['warnings'] = warnings

            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse(response_data)
            
            messages.success(request, success_msg)
            for warning in warnings:
                messages.warning(request, warning)
            return redirect('events:cfp_list')
    else:
        form = ProposalForm(instance=existing_proposal)
    
    context = {
        'form': form,
        'cfp': cfp,
        'proposal': existing_proposal,
        'is_edit': existing_proposal is not None,
        'now': timezone.now()  # Add current time for event status checks
    }
    # Get all session types for the dropdown
    session_types = SessionType.objects.all().order_by('name')
    
    return render(request, 'events/submit_proposal.html', {
        'cfp': cfp,
        'proposal': existing_proposal,
        'session_types': session_types,
        'now': now
    })

# Gallery Views
def gallery_view(request):
    """Display all gallery photos with event filtering"""
    events = Event.objects.filter(gallery__isnull=False).distinct()
    gallery_items = Gallery.objects.select_related('event').all().order_by('-event__date_time')
    
    return render(request, 'events/gallery.html', {
        'events': events,
        'gallery_items': gallery_items
    })

def event_gallery_view(request, event_id):
    """Display gallery photos for a specific event"""
    event = get_object_or_404(Event, id=event_id)
    gallery_items = Gallery.objects.filter(event=event).order_by('-id')
    
    return render(request, 'events/event_gallery.html', {
        'event': event,
        'gallery_items': gallery_items
    })

# Registration Views
@login_required
def register_for_event(request, event_id):
    """Handle event registration"""
    event = get_object_or_404(Event, id=event_id)
    
    # Check if event is available for registration
    now = timezone.now()
    two_hours_ago = now - timezone.timedelta(hours=2)
    
    if not event.is_upcoming:
        if event.is_ongoing:
            messages.error(request, 'This event is currently ongoing and cannot be registered for.')
        else:
            messages.error(request, 'This event has already ended.')
        return redirect('events:event_detail', event_id=event_id)
    
    # Check if registration is open
    if not event.registration_open:
        messages.error(request, 'Registration for this event is not open yet.')
        return redirect('events:event_detail', event_id=event_id)
    
    # Check if user is already registered
    registration = Registration.objects.filter(event=event, user=request.user).first()
    if registration:
        if registration.status == 'cancelled':
            # Allow re-registration if previously cancelled
            registration.status = 'registered'
            registration.registration_date = timezone.now()
            registration.save()
            messages.success(request, f'Successfully re-registered for {event.title}!')
        else:
            messages.warning(request, 'You are already registered for this event.')
        return redirect('events:event_detail', event_id=event_id)
    
    # Create new registration
    Registration.objects.create(
        event=event,
        user=request.user,
        status='registered'
    )
    messages.success(request, f'Successfully registered for {event.title}!')
    return redirect('events:event_detail', event_id=event_id)

@login_required
def cancel_registration(request, event_id):
    """Handle event registration cancellation"""
    event = get_object_or_404(Event, id=event_id)
    registration = get_object_or_404(Registration, event=event, user=request.user)
    
    # Check if event is still upcoming
    if not event.is_upcoming:
        if event.is_ongoing:
            messages.error(request, 'Cannot cancel registration for an ongoing event.')
        else:
            messages.error(request, 'Cannot cancel registration for a past event.')
        return redirect('events:event_detail', event_id=event_id)
    
    if registration.status == 'attended':
        messages.error(request, 'Cannot cancel registration for an event you have already attended.')
    else:
        registration.status = 'cancelled'
        registration.save()
        messages.success(request, f'Registration cancelled for {event.title}.')
    
    return redirect('events:event_detail', event_id=event_id)

# Archive Views
def archive_view(request):
    """Display archived events (events that are more than 2 hours old)"""
    now = timezone.now()
    
    # Get archived events (more than 2 hours old)
    # The Event model automatically updates status to 'archived'
    # when date_time is more than 2 hours old
    archived_events = Event.objects.filter(status='archived').order_by('-date_time')
    
    context = {
        'archived_events': archived_events
    }
    return render(request, 'events/archive.html', context)