from django.shortcuts import render, redirect, get_object_or_404
from django.http import JsonResponse, HttpResponse
from django.contrib import messages
from django.utils import timezone
from django.db.models import Count
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required
import csv
from datetime import datetime
from .models import RegisteredUser, Attendance


@login_required
def dashboard(request):
    # Force refresh of attendance statistics to ensure accuracy
    # This is important when users have been deleted
    
    # Step 1: Clean up any orphaned attendance records
    Attendance.objects.filter(user__isnull=True).delete()
    
    # Step 2: Reset attendance status for all users
    # This ensures we're only counting users who have actual attendance records
    RegisteredUser.objects.all().update(has_attended=False, timestamp=None)
    
    # Step 3: Update attendance status based on existing attendance records
    for attendance in Attendance.objects.all():
        if attendance.user:
            attendance.user.has_attended = True
            attendance.user.timestamp = attendance.check_in_time
            attendance.user.save()
    
    # Get statistics for the dashboard - use registration module as source of truth
    from registration.models import Registration
    total_registered = Registration.objects.count()
    total_attended = RegisteredUser.objects.filter(has_attended=True).count()
    attendance_percentage = 0 if total_registered == 0 else (total_attended / total_registered) * 100
    
    # Get total number of configured events (from Registration module - single source of truth)
    from registration.models import Event as RegistrationEvent
    
    # Use registration module events as the authoritative source
    events = RegistrationEvent.objects.filter(is_active=True).order_by('name')
    total_events = events.count()
    
    # Get attendance by event - use registration data as source of truth
    event_stats = []
    
    # Import Registration model to get actual registration counts
    from registration.models import Registration
    
    for event in events:
        event_name = event.name.strip()
        
        # Count actual registrations for this specific event
        registered = Registration.objects.filter(event=event).count()
        
        # Count attended users for this event (from attendance records)
        attended = 0
        attendances = Attendance.objects.filter(event_name=event_name)
        
        # Also try case-insensitive match for attendance records
        if not attendances.exists():
            attendances = Attendance.objects.filter(event_name__iexact=event_name)
        
        attended = attendances.count()
        
        # Calculate percentage
        percentage = 0 if registered == 0 else (attended / registered) * 100
        
        # Add to event stats
        event_stats.append({
            'id': event.id,
            'name': event.name,
            'date': event.start_date.date() if hasattr(event, 'start_date') else None,
            'registered': registered,
            'attended': attended,
            'percentage': round(percentage, 1)
        })
    
    # If there are no configured events but there are legacy events in RegisteredUser,
    # fall back to the old method to ensure backward compatibility
    if not event_stats and total_registered > 0:
        legacy_events = RegisteredUser.objects.values('event_name').distinct()
        
        for event in legacy_events:
            event_name = event['event_name']
            registered = RegisteredUser.objects.filter(event_name=event_name).count()
            attended = RegisteredUser.objects.filter(event_name=event_name, has_attended=True).count()
            percentage = 0 if registered == 0 else (attended / registered) * 100
            event_stats.append({
                'id': None,  # No ID for legacy events
                'name': event_name,
                'date': None,  # No date for legacy events
                'registered': registered,
                'attended': attended,
                'percentage': round(percentage, 1)
            })
    
    context = {
        'total_registered': total_registered,
        'total_attended': total_attended,
        'attendance_percentage': round(attendance_percentage, 1),
        'total_events': total_events,
        'event_stats': event_stats,
    }
    
    return render(request, 'attendance/dashboard.html', context)


@login_required
def attendance_list(request):
    # Get filter parameters
    event_filter = request.GET.get('event', '')
    attendance_filter = request.GET.get('attendance', '')
    search_query = request.GET.get('search', '')
    
    # Import registration models
    from registration.models import Registration
    
    # If an event is selected, show users for that event with attendance status
    if event_filter:
        # Get all registrations for this event
        registrations = Registration.objects.filter(event__name=event_filter)
        
        # Get attendance records for this event
        attendances = Attendance.objects.filter(event_name=event_filter)
        attended_codes = set(a.user.registration_code for a in attendances if a.user)
        
        # Create a list of user data with attendance status
        users_data = []
        for reg in registrations:
            has_attended = reg.registration_code in attended_codes
            
            # Apply attendance filter
            if attendance_filter == 'attended' and not has_attended:
                continue
            elif attendance_filter == 'not_attended' and has_attended:
                continue
            
            users_data.append({
                'registration_code': reg.registration_code,
                'full_name': reg.full_name,
                'email': reg.email,
                'event_name': reg.event.name,
                'organisation': getattr(reg, 'organisation', ''),
                'payment_status': getattr(reg, 'payment_status', 'Not Required'),
                'has_attended': has_attended,
                'timestamp': reg.registered_at,
            })
        
        users = users_data
    else:
        # Base queryset when no event is selected - show all registrations
        registrations = Registration.objects.all().select_related('event')
        
        # Get all attendance records to check attendance status
        attendances = Attendance.objects.all()
        attended_codes = set(a.user.registration_code for a in attendances if a.user)
        
        users_data = []
        for reg in registrations:
            has_attended = reg.registration_code in attended_codes
            
            # Apply attendance filter
            if attendance_filter == 'attended' and not has_attended:
                continue
            elif attendance_filter == 'not_attended' and has_attended:
                continue
            
            users_data.append({
                'registration_code': reg.registration_code,
                'full_name': reg.full_name,
                'email': reg.email,
                'event_name': reg.event.name,
                'organisation': getattr(reg, 'organisation', ''),
                'payment_status': getattr(reg, 'payment_status', 'Not Required'),
                'has_attended': has_attended,
                'timestamp': reg.registered_at,
            })
        
        users = users_data
    
    # Apply search filter if specified
    if search_query:
        filtered_users = []
        for user in users:
            if (search_query.lower() in user['full_name'].lower() or 
                search_query.lower() in user['registration_code'].lower() or 
                search_query.lower() in user['email'].lower()):
                filtered_users.append(user)
        users = filtered_users
    
    # Get list of events for the filter dropdown based on user permissions
    from .models import RegistrationEventAssignment
    from registration.models import Event as RegistrationEvent
    
    # Filter events based on user permissions
    if request.user.is_superuser:
        # Superusers see all registration events
        events = list(RegistrationEvent.objects.filter(is_active=True).values_list('name', flat=True).order_by('name'))
    else:
        # Regular users only see registration events assigned to them
        assignments = RegistrationEventAssignment.objects.filter(
            user=request.user, 
            is_active=True
        ).select_related('registration_event')
        events = [assignment.registration_event.name for assignment in assignments if assignment.registration_event.is_active]
    
    context = {
        'users': users,
        'events': events,
        'event_filter': event_filter,
        'attendance_filter': attendance_filter,
        'search_query': search_query,
    }
    
    return render(request, 'attendance/attendance_list.html', context)


@csrf_exempt
@login_required
def scan_barcode(request):
    if request.method == 'POST':
        registration_code = request.POST.get('registration_code', '')
        event_name = request.POST.get('event_name', '')
        event_id = request.POST.get('event_id', '')
        
        # If event_id is provided (from assigned event), get the event name
        if event_id and not event_name:
            from registration.models import Event as RegistrationEvent
            try:
                event = RegistrationEvent.objects.get(id=event_id)
                event_name = event.name
            except RegistrationEvent.DoesNotExist:
                pass
        
        if not registration_code or not event_name:
            return JsonResponse({'success': False, 'message': 'Registration code and event name are required'})
        
        # First, try to find user in attendance module (RegisteredUser)
        attendance_user = None
        registration_user = None
        
        try:
            attendance_user = RegisteredUser.objects.get(registration_code=registration_code)
        except RegisteredUser.DoesNotExist:
            pass
        
        # Also check registration module for approved registrations
        from registration.models import Registration
        try:
            registration_user = Registration.objects.get(
                registration_code=registration_code,
                event__name=event_name,
                status='approved',
                payment_status__in=['approved', 'not_required']
            )
        except Registration.DoesNotExist:
            pass
        
        # If no user found in either module
        if not attendance_user and not registration_user:
            return JsonResponse({
                'success': False, 
                'message': 'Registration code not found or not approved for attendance'
            })
        
        # Determine which user data to use (prioritize attendance module for backward compatibility)
        if attendance_user:
            user = attendance_user
            user_source = 'attendance'
            user_data = {
                'full_name': user.full_name,
                'email': user.email,
                'registration_code': user.registration_code,
                'event_name': event_name,
                'package_name': getattr(user, 'package_name', 'N/A'),
                'payment_status': getattr(user, 'payment_status', 'N/A'),
                'source': 'Attendance Module'
            }
        else:
            user = registration_user
            user_source = 'registration'
            user_data = {
                'full_name': user.full_name,
                'email': user.email,
                'registration_code': user.registration_code,
                'event_name': event_name,
                'package_name': f"{user.event.name} Registration",
                'payment_status': user.get_payment_status_display(),
                'source': 'Registration Module'
            }
        
        # Check if user has already attended this event
        if user_source == 'attendance':
            already_attended = Attendance.objects.filter(
                user=user,
                event_name=event_name
            ).exists()
        else:
            # For registration users, check both Attendance table and registration has_attended flag
            # Also check if a RegisteredUser exists with this registration code
            registered_user_exists = RegisteredUser.objects.filter(registration_code=registration_code).exists()
            
            if registered_user_exists:
                # Check attendance through RegisteredUser
                already_attended = Attendance.objects.filter(
                    user__registration_code=registration_code,
                    event_name=event_name
                ).exists()
            else:
                # Only check registration has_attended flag
                already_attended = user.has_attended
        
        if already_attended:
            # User has already attended this event
            return JsonResponse({
                'success': True, 
                'already_attended': True,
                'message': 'User has already been marked as attended',
                'user': user_data
            })
        else:
            # Create new attendance record
            if user_source == 'attendance':
                attendance = Attendance.objects.create(
                    user=user,
                    event_name=event_name,
                    check_in_time=timezone.now()
                )
                
                # Update user's attendance status
                if not user.has_attended:
                    user.has_attended = True
                    user.timestamp = timezone.now()
                    user.save()
            else:
                # For registration users, create attendance record with registration code
                # First, create or get a corresponding RegisteredUser record
                registered_user, created = RegisteredUser.objects.get_or_create(
                    registration_code=registration_code,
                    defaults={
                        'full_name': user.full_name,
                        'email': user.email,
                        'event_name': event_name,
                        'status': 'approved',
                        'package_name': f"{user.event.name} Registration",
                        'package_description': f"Registration for {user.event.name}",
                        'activity_price': user.event.amount if user.event.amount else 0.00,
                        'payment_status': user.get_payment_status_display(),
                        'has_attended': False,
                        'timestamp': timezone.now()
                    }
                )
                
                attendance = Attendance.objects.create(
                    user=registered_user,
                    event_name=event_name,
                    check_in_time=timezone.now()
                )
                
                # Update registration attendance status
                user.has_attended = True
                user.attendance_timestamp = timezone.now()
                user.save()
                
                # Update registered user attendance status
                if not registered_user.has_attended:
                    registered_user.has_attended = True
                    registered_user.timestamp = timezone.now()
                    registered_user.save()
            
            return JsonResponse({
                'success': True, 
                'already_attended': False,
                'message': 'Attendance recorded successfully',
                'user': user_data
            })
    
    return JsonResponse({'success': False, 'message': 'Invalid request method'})


@login_required
def scanner(request):
    # Initialize variables
    assigned_events = []
    assigned_event = None
    show_dropdown = True
    events = []
    
    # Import models at the beginning of the function to avoid scope issues
    from .models import RegistrationEventAssignment
    from registration.models import Event as RegistrationEvent
    
    if request.user.is_authenticated and not request.user.is_superuser:
        # Get the user's assigned registration event(s)
        assignments = RegistrationEventAssignment.objects.filter(
            user=request.user, 
            is_active=True
        ).select_related('registration_event')
        
        if assignments.exists():
            # Get all assigned registration events for this user
            assigned_events = [assignment.registration_event for assignment in assignments]
            
            if len(assigned_events) == 1:
                # If only one event is assigned, use it directly
                assigned_event = assigned_events[0]
                show_dropdown = False  # No need for dropdown with just one event
            else:
                # If multiple events are assigned, show a dropdown with only those events
                events = assigned_events
                show_dropdown = True
        
    # If superuser, show all registration events
    if request.user.is_superuser and show_dropdown:
        # Get events from the Registration Event model
        events = RegistrationEvent.objects.filter(is_active=True).order_by('name')
    # For staff users with no assignments, don't show any events
    elif not assigned_events and request.user.is_staff:
        events = []
        show_dropdown = False
    
    # Get event_id from query parameter if provided (for switching between assigned events)
    event_id = request.GET.get('event_id')
    if event_id and assigned_events:
        # If event_id is provided and user has assignments, try to find the matching event
        try:
            selected_event = RegistrationEvent.objects.get(id=event_id)
            if selected_event in assigned_events:
                assigned_event = selected_event
        except RegistrationEvent.DoesNotExist:
            pass
    
    context = {
        'events': events,
        'assigned_events': assigned_events,
        'assigned_event': assigned_event,
        'show_dropdown': show_dropdown,
    }
    
    return render(request, 'attendance/scanner.html', context)


@login_required
def export_attendance_csv(request):
    # Get filter parameters
    event_filter = request.GET.get('event', '')
    event_id = request.GET.get('event_id', '')
    
    # Customize filename based on event
    filename = 'attendance_export'
    
    # If event_id is provided, get the event name
    if event_id:
        from registration.models import Event as RegistrationEvent
        try:
            event = RegistrationEvent.objects.get(id=event_id)
            event_filter = event.name
            filename = f'attendance_{event.name.replace(" ", "_").lower()}'
        except RegistrationEvent.DoesNotExist:
            pass
    
    # If event_filter is provided, customize filename
    if event_filter and not event_id:
        filename = f'attendance_{event_filter.replace(" ", "_").lower()}'
    
    # Initialize users_data list
    users_data = []
    
    # Import registration models
    from registration.models import Registration
    
    # If an event is selected, export all users for that event with attendance status
    if event_filter:
        # Get all registrations for this event
        registrations = Registration.objects.filter(event__name=event_filter)
        
        # Get attendance records for this event
        attendances = Attendance.objects.filter(event_name=event_filter)
        attended_codes = set(a.user.registration_code for a in attendances if a.user)
        
        # Create a list of user data with attendance information
        for reg in registrations:
            has_attended = reg.registration_code in attended_codes
            attendance_record = None
            
            # Find the attendance record for timestamp
            for att in attendances:
                if att.user and att.user.registration_code == reg.registration_code:
                    attendance_record = att
                    break
            
            users_data.append({
                'registration_code': reg.registration_code,
                'full_name': reg.full_name,
                'email': reg.email,
                'event_name': reg.event.name,
                'organisation': getattr(reg, 'organisation', ''),
                'payment_status': getattr(reg, 'payment_status', 'Not Required'),
                'attended': has_attended,
                'timestamp': attendance_record.check_in_time if attendance_record else reg.registered_at
            })
    else:
        # If no event filter, export all registrations with attendance status
        registrations = Registration.objects.all().select_related('event')
        
        # Get all attendance records
        attendances = Attendance.objects.all()
        attended_codes = set(a.user.registration_code for a in attendances if a.user)
        
        for reg in registrations:
            has_attended = reg.registration_code in attended_codes
            attendance_record = None
            
            # Find the attendance record for timestamp
            for att in attendances:
                if att.user and att.user.registration_code == reg.registration_code:
                    attendance_record = att
                    break
            
            users_data.append({
                'registration_code': reg.registration_code,
                'full_name': reg.full_name,
                'email': reg.email,
                'event_name': reg.event.name,
                'organisation': getattr(reg, 'organisation', ''),
                'payment_status': getattr(reg, 'payment_status', 'Not Required'),
                'attended': has_attended,
                'timestamp': attendance_record.check_in_time if attendance_record else reg.registered_at
            })
    
    # Create the HttpResponse object with CSV header
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = f'attachment; filename="{filename}.csv"'
    
    # Create CSV writer
    writer = csv.writer(response)
    
    # Write header row
    writer.writerow(['Registration Code', 'Full Name', 'Email', 'Event', 'Organisation', 'Payment Status', 'Attended', 'Timestamp'])
    
    # Write data rows
    for data in users_data:
        writer.writerow([
            data['registration_code'],
            data['full_name'],
            data['email'],
            data['event_name'],
            data['organisation'],
            data['payment_status'],
            'Yes' if data['attended'] else 'No',
            data['timestamp'].strftime('%Y-%m-%d %H:%M:%S') if data['timestamp'] else ''
        ])
    
    return response
