import json, os
from openpyxl import load_workbook
from django.db import transaction
from datetime import timedelta
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import authenticate, login, logout
from django.http import JsonResponse
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils import timezone
from twilio.rest import Client
from decouple import config
from django.conf import settings
from django.db.models import Q
from .models import Accreditation, RSVP
from .utils import send_registration_confirmation_email, send_birthday_invitation_email, merge_qr_with_invite
import logging

# Send WhatsApp Message
account_sid = config('TWILIO_ACCOUNT_SID')
auth_token = config('TWILIO_AUTH_TOKEN')
messaging_service_sid = "MG018ee670d457100f1e059c498af63ce3"
client = Client(account_sid, auth_token)

logger = logging.getLogger(__name__)

# Index
def index(request):
    return render(request, 'index.html')
    
def register(request):
    return redirect('https://flyingfishsurprisinglygoodsets.com/self-accredit/')

# Accreditation
def accreditation(request):
    return render(request, 'accreditation.html')

def search_guests(request):
    """Search for guests by first name or last name prefix"""
    if request.method == 'GET':
        query = request.GET.get('q', '').strip()

        if len(query) >= 2:
            rsvp_results = RSVP.objects.filter(name__icontains=query).order_by('name')

            ticket_list = []

            # Get today's accreditations
            today = timezone.now().date()
            tomorrow = today + timezone.timedelta(days=1)
            rsvp_accreditations = set(Accreditation.objects.filter(
                rsvp__in=rsvp_results,
                date__gte=today,
                date__lt=tomorrow,
                is_accredited=True
            ).values_list('rsvp_id', flat=True))

            # Process RSVP results
            for rsvp in rsvp_results:
                ticket_list.append({
                    'id': rsvp.id,
                    'name': rsvp.name,
                    'email': rsvp.email,
                    'phone': rsvp.phone,
                    'type': 'rsvp',
                    'total_quantity': 1,
                    'is_accredited': rsvp.id in rsvp_accreditations,
                })

            return JsonResponse({'tickets': ticket_list})
        else:
            return JsonResponse({'tickets': []})

    return JsonResponse({'status': 405, 'message': 'Method Not Allowed!'})

@csrf_exempt
def check_in(request):
    if request.method == 'POST':
        name = request.POST.get('name')
        quantity_str = request.POST.get('quantity')
        accredit_all = request.POST.get('accredit_all') == 'true'

        if not name:
            return JsonResponse({'status': 400, 'message': 'Please provide ticket name'})
        
        # Try to find RSVP by name or ticket number
        rsvp = RSVP.objects.filter(
            Q(name__iexact=name) | Q(ticket_number__iexact=name)
        ).first()

        if not rsvp:
            return JsonResponse({'status': 404, 'message': 'RSVP not found'})

        # Handle RSVP check-in
        if rsvp:
            # Check if already accredited today
            today = timezone.now().date()
            tomorrow = today + timedelta(days=1)
            existing_accreditation = Accreditation.objects.filter(
                rsvp=rsvp, 
                is_accredited=True,
                date__gte=today,
                date__lt=tomorrow
            ).first()
            
            if quantity_str:
                # Process check-in with quantity
                if existing_accreditation:
                    return JsonResponse({'status': 400, 'message': 'This RSVP has already been checked in today'})

                # Check in the RSVP
                Accreditation.objects.create(
                    rsvp=rsvp,
                    is_accredited=True
                )

                return JsonResponse({
                    'status': 200,
                    'message': 'RSVP checked in successfully',
                    'guest': {
                        'name': rsvp.name,
                        'email': rsvp.email,
                        'phone': rsvp.phone,
                        'accredited_quantity': 1,
                        'total_quantity': 1,
                        'type': 'rsvp'
                    }
                })
            else:
                # Return ticket info for modal
                is_accredited_today = existing_accreditation is not None
                ticket_info = {
                    'name': rsvp.name,
                    'email': rsvp.email,
                    'phone': rsvp.phone,
                    'accredited_quantity': 1 if is_accredited_today else 0,
                    'total_quantity': 1,
                    'remaining_quantity': 0 if is_accredited_today else 1,
                    'current_date': timezone.now().strftime('%Y-%m-%d'),
                    'type': 'rsvp'
                }
                return JsonResponse({'status': 200, 'ticket': ticket_info})

    return JsonResponse({'status': 405, 'message': 'Method not allowed'})

# RSVP
def rsvp(request):
    return render(request, 'rsvp.html')

# RSVP Submit
@require_http_methods(["POST"])
def rsvp_submit(request):
    if request.method == 'POST':
        first_name = request.POST.get('first_name', '').strip()
        last_name = request.POST.get('last_name', '').strip()
        email = request.POST.get('email', '').strip()
        phone = request.POST.get('phone', '').strip()

        # Validate required fields
        if not all([first_name, email, phone]):
            return JsonResponse({
                'success': False,
                'message': 'First name, email, and phone are required'
            }, status=400)
                            
        if RSVP.objects.filter(email=email).exists():
            return JsonResponse({
                'success': False,
                'message': 'Email is already registered'
            }, status=400)

        # Validate email format
        try:
            validate_email(email)
        except ValidationError:
            return JsonResponse({
                'success': False,
                'message': 'Please enter a valid email address'
            }, status=400)

        # Create RSVP record
        rsvp = RSVP(
            name = f"{first_name} {last_name}",
            first_name=first_name,
            last_name=last_name,
            email=email,
            phone=phone,
        )
        rsvp.save()
        try:
            if rsvp.email:
                send_registration_confirmation_email(rsvp)
            
            if rsvp.phone:
                content_sid = "HX994e10d7bfa54ccd1b83de4e497b5e15"
                to_number = f"whatsapp:{rsvp.phone}"
        
                content_variables = json.dumps({
                    "name": rsvp.name,
                })
                try:
                    client.messages.create(
                        content_sid=content_sid,
                        to=to_number,
                        from_=messaging_service_sid,
                        content_variables=content_variables
                    )
                except Exception as e:
                    logger.error(f"Error sending WhatsApp message: {str(e)}")
                                
            return JsonResponse({
                'success': True,
                'message': 'Thank you for your RSVP!'
            })

        except Exception as e:
            logger.error(f"Error submitting RSVP: {str(e)}")
            return JsonResponse({
                'success': False,
                'message': str(e)
            }, status=400)

    return JsonResponse({'status': False, 'message': 'Method not allowed'}, status=405)

# Send QR Code
@login_required
def send_qr_code(request):
    if request.method == 'POST':
        rsvp_id = request.POST.get('rsvp_id')

        if not rsvp_id:
            return JsonResponse({'status': 400, 'message': "RSVP ID is required"}, status=400)

        try:
            rsvp = RSVP.objects.get(pk=rsvp_id)
            
            # Birthday Invitation
            try:
                # if rsvp.email:
                #     send_birthday_invitation_email(rsvp)
            
                if rsvp.phone:
                    # content_sid = "HXf7d08dd02e00c82ca8a407768e170cd7" #Reminder
                    content_sid = "HX63d930de5f37b5124afc7c436668f731"
                    to_number = f"whatsapp:{rsvp.phone}"
        
                content_variables = json.dumps({
                    "1": getattr(rsvp, 'name', ''),
                    "2": f"access/{getattr(rsvp, 'ticket_number', '')}",
                })
                try:
                    msg = client.messages.create(
                        content_sid=content_sid,
                        to=to_number,
                        from_=messaging_service_sid,
                        content_variables=content_variables
                    )
                except Exception as e:
                    logger.error(f"Error sending WhatsApp message: {str(e)}")
                    
                rsvp.is_sent = True
                rsvp.message_sid = msg.sid
                rsvp.save()
                
                return JsonResponse({'status': 200, 'message': 'QR code sent successfully!'})

            except Exception as e:
                logger.error(f"Error submitting RSVP: {str(e)}")
                return JsonResponse({'status': 400, 'message': str(e)})
            
        except RSVP.DoesNotExist:
            return JsonResponse(
                {'status': 404, 'message': 'RSVP not found'},
                status=404
            )
        except Exception as e:
            return JsonResponse(
                {'status': 500, 'message': f'Error sending QR code: {str(e)}'},
                status=500
            )
    return JsonResponse(
        {'status': 405, 'message': 'Method not allowed'},
        status=405
    )

# Send Bulk QR Codes
@login_required
@csrf_exempt
def send_bulk_qr_codes(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({'status': 400, 'message': "Invalid JSON data"}, status=400)
        rsvp_ids = data.get('rsvp_ids', [])

        if not rsvp_ids:
            return JsonResponse({'status': 400, 'message': "No RSVP IDs provided"}, status=400)

        sent_count = 0
        failed_rsvps = []

        for rsvp_id in rsvp_ids:
            try:
                rsvp = RSVP.objects.get(pk=rsvp_id)

                # Birthday Invitation
              
                try:
                    # if rsvp.email:
                    #     send_birthday_invitation_email(rsvp)
                
                    if rsvp.phone:
                        # content_sid = "HXf7d08dd02e00c82ca8a407768e170cd7" #Reminder
                        content_sid = "HX63d930de5f37b5124afc7c436668f731"
                        to_number = f"whatsapp:{rsvp.phone}"
            
                    content_variables = json.dumps({
                        "1": getattr(rsvp, 'name', ''),
                        "2": f"access/{getattr(rsvp, 'ticket_number', '')}",
                    })
                    try:
                        msg = client.messages.create(
                            content_sid=content_sid,
                            to=to_number,
                            from_=messaging_service_sid,
                            content_variables=content_variables
                        )
                    except Exception as e:
                        logger.error(f"Error sending WhatsApp message: {str(e)}")
                    
                    rsvp.is_sent = True
                    rsvp.message_sid = msg.sid
                    rsvp.save()
                    sent_count += 1
                    
                    return JsonResponse({'status': 200, 'message': 'QR code sent successfully!'})

                except Exception as e:
                    logger.error(f"Error submitting RSVP: {str(e)}")
                    failed_rsvps.append(f"RSVP ID {rsvp_id} (error: {str(e)})")
                    return JsonResponse({'status': 400, 'message': str(e)})

            except RSVP.DoesNotExist:
                failed_rsvps.append(f"RSVP ID {rsvp_id} (not found)")
            except Exception as e:
                failed_rsvps.append(f"RSVP ID {rsvp_id} (error: {str(e)})")

        message = f"QR codes sent to {sent_count} RSVP attendee(s)."
        if failed_rsvps:
            message += f" Failed for: {', '.join(failed_rsvps)}."

        return JsonResponse({
            'status': 200,
            'message': message,
            'sent_count': sent_count
        })

    return JsonResponse(
        {'status': 405, 'message': 'Method not allowed'},
        status=405
    )

@login_required
def reset_rsvp_status(request):
    if request.method == 'POST':
        RSVP.objects.filter(is_sent=True).update(is_sent=False)
        return JsonResponse({'status': 200, 'message': 'Status has been reset.'})
    return JsonResponse(
        {'status': 405, 'message': 'Method not allowed'},
        status=405
    )

# Delete RSVP
@login_required
@csrf_exempt
@require_http_methods(["DELETE"])
def delete_rsvp(request, rsvp_id):
    try:
        rsvp = get_object_or_404(RSVP, id=rsvp_id)
        rsvp.delete()
        return JsonResponse({'success': True, 'message': 'RSVP deleted successfully'})
    except Exception as e:
        logger.error(f'Error deleting RSVP {rsvp_id}: {str(e)}')
        return JsonResponse({'success': False, 'message': str(e)}, status=500)

@login_required
@csrf_exempt
@require_http_methods(["POST"])
def edit_rsvp(request, rsvp_id):
    try:
        rsvp = get_object_or_404(RSVP, id=rsvp_id)
        
        # Parse the request data
        data = json.loads(request.body)
        first_name = data.get('first_name')
        last_name = data.get('last_name', '')
        
        # Update RSVP fields
        rsvp.name = f"{first_name} {last_name}"
        rsvp.first_name = first_name
        rsvp.last_name = last_name
        rsvp.email = data.get('email', rsvp.email)
        rsvp.phone = data.get('phone', rsvp.phone)
        
        # Validate email format
        try:
            validate_email(rsvp.email)
        except ValidationError:
            return JsonResponse({
                'success': False,
                'message': 'Please enter a valid email address'
            }, status=400)
        
        # Save the updated RSVP
        rsvp.save()
        
        return JsonResponse({'success': True, 'message': 'RSVP updated successfully'})
    except RSVP.DoesNotExist:
        return JsonResponse({'success': False, 'message': 'RSVP not found'}, status=404)
    except json.JSONDecodeError:
        return JsonResponse({'success': False, 'message': 'Invalid JSON data'}, status=400)
    except Exception as e:
        logger.error(f'Error updating RSVP {rsvp_id}: {str(e)}')
        return JsonResponse({'success': False, 'message': str(e)}, status=500)

# Dashboard
@login_required
def dashboard(request):
    # Additional security check - ensure user is authenticated
    if not request.user.is_authenticated:
        from django.contrib.auth.views import redirect_to_login
        return redirect_to_login(request.get_full_path(), login_url='/login/')
    
    guests = RSVP.objects.all()
    context = {
        'guests': guests,
        'total_guest':  guests.count(),
        'total_accredited': Accreditation.objects.count(),
    }
    return render(request, 'dashboard.html', context)

# Accredited
@login_required
def accredited(request):
    accredited = Accreditation.objects.prefetch_related('rsvp').all().order_by('-date')
    context = {
        'guests': accredited,
        'total_accredited': accredited.count(),
        'total_guest':  RSVP.objects.count(),
    }
    return render(request, 'accredited.html', context)

# Login
def login_view(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        
        if username and password:
            user = authenticate(request, username=username, password=password)
            if user is not None:
                if user.is_staff:
                    login(request, user)
                    # Regenerate session to prevent session fixation
                    request.session.cycle_key()
                    return redirect('dashboard')
                else:
                    messages.error(request, "You do not have permission to access this dashboard.")
            else:
                messages.error(request, "Invalid credentials. Please check your username and password.")
        else:
            messages.error(request, "Username and password are required.")

    return render(request, 'login.html')

# Logout
@login_required
def logout_view(request):
    request.session.flush()
    logout(request)
    return redirect('login')

@login_required
def create_accesscard(request):
    if request.method == 'GET':
        qr_codes_dir = os.path.join(settings.MEDIA_ROOT, 'qr_codes')
        accesscards_dir = os.path.join(settings.MEDIA_ROOT, 'access')
        card_path = os.path.join(settings.MEDIA_ROOT, 'card.png')

        if not os.path.exists(card_path):
            return JsonResponse({'status': 400, 'message': 'card.png not found in media directory'})

        os.makedirs(accesscards_dir, exist_ok=True)

        processed_count = 0
        failed_files = []

        for filename in os.listdir(qr_codes_dir):
            if filename.endswith('.png'):
                qr_path = os.path.join(qr_codes_dir, filename)
                output_path = os.path.join(accesscards_dir, filename)
                try:
                    merge_qr_with_invite(card_path, qr_path, output_path)
                    processed_count += 1
                except Exception as e:
                    failed_files.append(f"{filename}: {str(e)}")

        message = f"Processed {processed_count} access cards."
        if failed_files:
            message += f" Failed: {', '.join(failed_files)}"

        return JsonResponse({'status': 200, 'message': message, 'processed': processed_count})

    return JsonResponse({'status': 405, 'message': 'Method not allowed'})

@login_required
def import_guests(request):
    if request.method != 'POST':
        return JsonResponse({'status': 405, 'message': 'Method not allowed'}, status=405)
        
    excel_file = request.FILES.get('guest_list')
    if not excel_file:
        return JsonResponse({'status': 400, 'message': 'No file uploaded'}, status=400)
        
    filename = excel_file.name.lower()
    imported_count = 0
    
    def clean_phone(value):
        if value is None:
            return None
        phone = str(value).strip()
        if not phone or phone.lower() == 'none':
            return None
        phone = phone.replace(' ', '')
        if phone.startswith('+'):
            return phone
        if phone.startswith('0'):
            return '+234' + phone[1:]
        if len(phone) == 10:
            return '+234' + phone
        return phone

    try:
        if filename.endswith('.csv'):
            decoded_file = excel_file.read().decode('utf-8-sig').splitlines()
            reader = csv.DictReader(decoded_file)
            headers = reader.fieldnames
            if not headers:
                return JsonResponse({'status': 400, 'message': 'Empty CSV headers'}, status=400)
                
            name_col = None
            phone_col = None
            category_col = None
            for h in headers:
                if not h:
                    continue
                h_clean = str(h).strip().lower()
                if h_clean in ['name', 'full name', 'guest name', 'names']:
                    name_col = h
                elif h_clean in ['phone', 'phone number', 'phone_number', 'phonenumber', 'mobile', 'mobile number', 'mobile_number', 'contact']:
                    phone_col = h
                elif h_clean in ['category', 'categories', 'guest type', 'type']:
                    category_col = h
                    
            if not name_col:
                for h in headers:
                    if not h:
                        continue
                    h_clean = str(h).strip().lower()
                    if 'name' in h_clean:
                        name_col = h
                        break
            if not phone_col:
                for h in headers:
                    if not h:
                        continue
                    h_clean = str(h).strip().lower()
                    if 'phone' in h_clean or 'mobile' in h_clean:
                        phone_col = h
                        break
            if not category_col:
                for h in headers:
                    if not h:
                        continue
                    h_clean = str(h).strip().lower()
                    if 'category' in h_clean or 'type' in h_clean:
                        category_col = h
                        break
                        
            if not name_col:
                return JsonResponse({
                    'status': 400, 
                    'message': f'Required header "name" not found. Headers found: {headers}'
                }, status=400)
                
            with transaction.atomic():
                for row in reader:
                    name = row.get(name_col, '').strip() if row.get(name_col) is not None else ''
                    phone = clean_phone(row.get(phone_col))
                    category = row.get(category_col, '').strip() if row.get(category_col) is not None else None if category_col else None
                    
                    if not name:
                        continue
                        
                    name_parts = name.split(maxsplit=1)
                    first_name = name_parts[0] if name_parts else ''
                    last_name = name_parts[1] if len(name_parts) > 1 else ''
                    
                    rsvp = RSVP(
                        name=name,
                        first_name=first_name,
                        last_name=last_name,
                        phone=phone,
                        category=category,
                    )
                    rsvp.save()
                    imported_count += 1
                    
        elif filename.endswith(('.xlsx', '.xls')):
            wb = load_workbook(excel_file, read_only=True)
            sheet = wb.active
            rows = list(sheet.iter_rows(values_only=True))
            if not rows:
                return JsonResponse({'status': 400, 'message': 'Empty Excel file'}, status=400)
                
            headers = [str(h).strip() if h is not None else '' for h in rows[0]]
            name_idx = None
            phone_idx = None
            category_idx = None
            
            for idx, h in enumerate(headers):
                h_clean = h.lower()
                if h_clean in ['name', 'full name', 'guest name', 'names']:
                    name_idx = idx
                elif h_clean in ['phone', 'phone number', 'phone_number', 'phonenumber', 'mobile', 'mobile number', 'mobile_number', 'contact']:
                    phone_idx = idx
                elif h_clean in ['category', 'categories', 'guest type', 'type']:
                    category_idx = idx
                    
            if name_idx is None:
                for idx, h in enumerate(headers):
                    h_clean = h.lower()
                    if 'name' in h_clean:
                        name_idx = idx
                        break
            if phone_idx is None:
                for idx, h in enumerate(headers):
                    h_clean = h.lower()
                    if 'phone' in h_clean or 'mobile' in h_clean:
                        phone_idx = idx
                        break
            if category_idx is None:
                for idx, h in enumerate(headers):
                    h_clean = h.lower()
                    if 'category' in h_clean or 'type' in h_clean:
                        category_idx = idx
                        break
                        
            if name_idx is None:
                return JsonResponse({
                    'status': 400, 
                    'message': f'Required column "name" not found. Headers found: {headers}'
                }, status=400)
                
            with transaction.atomic():
                for row in rows[1:]:
                    if len(row) <= max(name_idx, phone_idx):
                        continue
                    name = str(row[name_idx]).strip() if row[name_idx] is not None else ''
                    phone = clean_phone(row[phone_idx])
                    category = str(row[category_idx]).strip() if category_idx is not None and row[category_idx] is not None else None
                    
                    if not name:
                        continue
                        
                    name_parts = name.split(maxsplit=1)
                    first_name = name_parts[0] if name_parts else ''
                    last_name = name_parts[1] if len(name_parts) > 1 else ''
                    
                    # if RSVP.objects.filter(phone=phone).exists():
                    #     continue
                        
                    rsvp = RSVP(
                        name=name,
                        first_name=first_name,
                        last_name=last_name,
                        phone=phone,
                        category=category,
                    )
                    rsvp.save()
                    imported_count += 1
        else:
            return JsonResponse({'status': 400, 'message': 'Unsupported file format. Please upload CSV or Excel (.xlsx, .xls) file.'}, status=400)
            
        return JsonResponse({
            'status': 200,
            'message': f'Successfully imported {imported_count} guests.'
        })
        
    except Exception as e:
        logger.error(f'Error importing guests: {str(e)}')
        return JsonResponse({'status': 500, 'message': f'Error importing guests: {str(e)}'}, status=500)


