from datetime import timedelta
from collections import defaultdict
from datetime import date
from datetime import datetime, time
from django.utils import timezone

from django.db.models import Q
from django.db.models import Sum
from django.db.models import Count

from django.shortcuts import render, redirect,get_object_or_404
from django.shortcuts import render, HttpResponse, redirect, HttpResponseRedirect

from django.utils.http import urlsafe_base64_encode
from django.utils.http import urlsafe_base64_decode
from django.utils.encoding import force_str
from django.utils.encoding import force_bytes

from django.contrib.auth.decorators import login_required
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth import authenticate, login, logout as auth_logout
from django.contrib.auth import update_session_auth_hash
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test

from .tokens import account_activation_token
from django.views.generic import TemplateView
from django.urls import reverse, reverse_lazy
from django.core.mail import send_mail
from django.template.loader import render_to_string

#models
from .models import CustomUser
from .models import Organisation
from .models import Nominations
from .models import PostEventReport
from .models import COPEventAnnouncement
from .models import COPEventApplication
from .models import Invoice
from .models import Bilateral
from .models import BilateralReport
from .models import EventResources
from .models import Activist
from .models import Event
from .models import Attendane

#forms
from django import forms
from .forms import OrgEventForm
from .forms import RegisterForm
from .forms import InvoiceForm
from .forms import PaidForm
from .forms import CustomPasswordResetForm
from .forms import CustomSetPasswordForm
from .forms import CustomPasswordChangeForm
from .forms import OrganisationForm
from .forms import StatusForm
from .forms import EventForm
from .forms import ReportForm
from .forms import AnnouncementForm
from .forms import AddOrgForm
from .forms import NominationForm
from .forms import NominationApproval
from .forms import AdminForm
from .forms import AdminUpdateForm
from .forms import ComfirmForm
from .forms import MeetingForm
from .forms import ReportMeetingForm
from .forms import ResourcesForm
from .forms import AttendaneForm

from django.http import JsonResponse
from django.views.decorators.http import require_GET

@require_GET
def get_time_options(request):
    day = request.GET.get('day')
    form = EventForm()
    time_slots = form.get_filtered_time_slots(day)
    
    if not time_slots:
        return JsonResponse({"message": "No available slots left on this day"}, safe=False)
    
    return JsonResponse(time_slots, safe=False)



# Create your views here.
handler404 = TemplateView.as_view(template_name="404.html")

def is_admin(user):
    return user.is_authenticated and user.role == 'Admin'

def is_event_manager(user):
    return user.is_authenticated and user.role == 'Event Manager'

def is_finance(user):
    return user.is_authenticated and user.role == 'Finance'

def is_bilaterals(user):
    return user.is_authenticated and user.role == 'Bilaterals'

def is_cop_desk_officer(user):
    return user.is_authenticated and user.role == 'COP Desk Officer'

def is_organisation(user):
    return user.is_authenticated and user.role == 'Organisation'

def is_individual(user):
    return user.is_authenticated and user.role == 'Individual'


def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        print(f"Decoded UID: {uid}")

        user = CustomUser.objects.get(pk=uid)

        print(f"Fetched user with email: {user.email}")
    except (TypeError, ValueError, OverflowError) as e:
        print(f"Error while decoding UID: {e}")
        user = None
    except CustomUser.DoesNotExist:
        print(f"No user found with UID: {uid}")
        user = None

    if user is not None and account_activation_token.check_token(user, token):
        user.is_verified = True
        user.save()
        return redirect(reverse('login'))
    else:
        return HttpResponse('Activation link is invalid!')

def index(request):
    
    context = {
        
    }

    return render(request, 'home.html', context)

def dashboard(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today),
        status='Approved',
    )

    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }

    return render(request, 'dashboard.html', context)


def signin(request):
    context = {}

    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)

        if user is not None:
            if user.is_verified: 
                login(request, user)

                try:
                    user_role = user.role 
                    if user_role == 'Admin':
                        return redirect('admin-dash')
                    elif user_role == 'COP Desk Officer':
                        return redirect('admin-cop')
                    elif user_role == 'Event Manager':
                        return redirect('event-dash')
                    elif user_role == 'Finance':
                        return redirect('fin-dash')
                    elif user_role == 'Bilaterals':
                        return redirect('bil-dash')
                    elif user_role == 'Organisation':
                        if Organisation.objects.filter(user=user).exists():
                            return redirect('org_dashbord')
                        else:
                            return redirect('org_profile')
                    elif user_role == 'Individual':
                        return redirect('activist')
                    else:
                        context['error_message'] = 'Contact the administrator for a designated role.'
                except: 
                    context['error_message'] = 'Dashboard Error'
            else:
                context['login_error'] = 'Account is not verified. Please check your emails and verify your account first.'
        else:
            context['login_error'] = 'Invalid credentials.'

    return render(request, 'account/login.html', context)

def loggingout(request):
    auth_logout(request)
    return redirect('login')

def Register(request):
    form = RegisterForm()

    if request.method == "POST":
        form = RegisterForm(request.POST)
        if form.is_valid():
            register = form.save()

            try:
                register.send_verification_email(request)
                messages.success(
                    request, 'A verification email has been sent to your email address.')
                return redirect('home')

                # Handle error (could log it, notify admins, or inform the user)
            except Exception as e:
                messages.error(
                    request, f'There was an error sending the verification email: {e}')

    context = {
        'form': form,
    }
    return render(request, 'account/register.html', context)


def custom_password_reset(request):
    if request.method == "POST":
        form = CustomPasswordResetForm(request.POST)
       
        if form.is_valid():
            email = form.cleaned_data['email']
            try:
                user = CustomUser.objects.get(email=email)
                token = default_token_generator.make_token(user)
                uid = urlsafe_base64_encode(force_bytes(user.pk))
                reset_link = request.build_absolute_uri(
                    reverse_lazy('password_reset_confirm', kwargs={
                        'uidb64': uid, 'token': token})
                )
                user_name = user.name
                user_email = user.email

                # Load the HTML email template
                html_message = render_to_string('account/password_reset_email.html', {'reset_link': reset_link, 'user_name': user_name, 'user_email': user_email})
                subject = 'Password Reset'
                from_email = 'admin@climateportal.org.ng'
                recipient_list = [email]

                # Sending the email with the custom template
                send_mail(subject, '', from_email, recipient_list, html_message=html_message)

                messages.success(request, 'A reset link has been sent to your email.')
                return redirect('login')
            except CustomUser.DoesNotExist:
                messages.error(request, 'User details not found, please register.')
                return redirect('register')
    else:
        form = CustomPasswordResetForm()
   
    return render(request, 'account/password_reset.html', {'form': form})


def password_reset_confirm(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = CustomUser.objects.get(pk=uid)
    except CustomUser.DoesNotExist:
        user = None

    if user is not None and default_token_generator.check_token(user, token):
        if request.method == "POST":
            form = CustomSetPasswordForm(user, request.POST)
            if form.is_valid():
                form.save()
                return redirect('login')
        else:
            form = CustomSetPasswordForm(user)
        return render(request, 'account/password_reset_confirm.html', {'form': form})


# @login_required
def change_password(request):
    if request.method == 'POST':
        form = CustomPasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            # Important, to update the session and keep the user authenticated
            update_session_auth_hash(request, user)
            messages.success(
                request, 'Your password was successfully updated! Please Login Again')
            return redirect('login')
        else:
            messages.error(request, 'Please correct the errors below.')
    else:
        form = CustomPasswordChangeForm(request.user)
    return render(request, 'account/update_password.html', {'form': form})

#Admin Dashboard
@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_dash(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today)
    )

    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }

    return render(request, 'admin/dashboard.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_org(request):
    members = Organisation.objects.all()

    mda = Organisation.objects.filter(organisation_type='GO/MDAs').count()
    ngo = Organisation.objects.filter(organisation_type='NGO/iNGO').count()
    private = Organisation.objects.filter(organisation_type='private').count()
    youth = Organisation.objects.filter(organisation_type='Women/YouthLead').count()

    form = AddOrgForm()

    if request.method == "POST":
        form = AddOrgForm(request.POST)
        if form.is_valid():
            org_instance = form.save(commit=False)
            org_instance.role = 'Organisation'
            
            # Use Django's set_password method to securely set the password
            org_instance.set_password('Nccc@COP28')

            org_instance.save()

            try:
                # Assuming send_verification_email is a method in your Organisation model
                org_instance.send_verification_email(request)

                messages.success(
                    request, 'A verification email has been sent to the organisation.')
                return redirect('organisations')

            except Exception as e:
                messages.error(
                    request, f'There was an error sending the verification email: {e}')

    context = {
        'members': members,
        'mda': mda,
        'ngo': ngo,
        'youth': youth,
        'private': private,
        'form': form
    }

    return render(request, 'admin/organisations.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_org_prof(request, pk):
    member_id = get_object_or_404(Organisation, pk=pk)
    instance = Organisation.objects.get(pk=pk)

    if request.method == 'POST':
        form = StatusForm(request.POST, instance=instance)
        if form.is_valid():
            user = request.user
            form = form.save(commit=False)
            form.approved_by = user
            form.save()
            #url = reverse('org_prof', kwargs={'pk': member_id.pk})
            return redirect('organisations')
    else:
        form = StatusForm(instance=instance)
    context = {
        'member_id': member_id,
        'form': form,
        
    }

    return render(request, 'admin/org_profile.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_users_list(request):
    users = CustomUser.objects.count()
    users_list = CustomUser.objects.exclude(role__in=["Organisation", "Activist"])
    total = users_list.count()
    form = AdminForm()

    if request.method == "POST":
        form = AdminForm(request.POST)
        if form.is_valid():
            register = form.save()

            try:
                register.send_verification_email(request)
                messages.success(
                    request, 'A verification email has been sent to the email address.')
                return redirect('admin-users-list')

                # Handle error (could log it, notify admins, or inform the user)
            except Exception as e:
                messages.error(
                    request, f'There was an error sending the verification email: {e}. Verify the user manually')

    context = {
        'form': form,
        'users': users,
        'users_list': users_list,
        'total': total
    }

    return render(request, 'admin/users.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_user_update(request, pk):
    member_id = get_object_or_404(CustomUser, pk=pk)
    instance = CustomUser.objects.get(pk=pk)

    if request.method == 'POST':
        form = AdminUpdateForm(request.POST, instance=instance)
        if form.is_valid():
            form = form.save(commit=False)
            form.save()
            #url = reverse('org_prof', kwargs={'pk': member_id.pk})
            return redirect('admin-users-list')
    else:
        form = AdminUpdateForm(instance=instance)
    context = {
        'member_id': member_id,
        'form': form,
        
    }

    return render(request, 'admin/user_detail.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_side_event(request):
    events = COPEventApplication.objects.all()
    application = COPEventApplication.objects.count()
    approve = COPEventApplication.objects.filter(status='Approved').count()
    hosted = PostEventReport.objects.count()

    form = EventForm()
    if request.method == 'POST':
        form = EventForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('side_event')
    
    else:
        form = EventForm()

    context = {
        'events': events,
        'form': form,
        'application': application,
        'approve': approve,
        'hosted': hosted,
    }

    return render(request, 'admin/side_event.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_normApp(request):
    norm = Nominations.objects.all()
    application = Nominations.objects.count()
    approve = Nominations.objects.filter(status='Approved').count()
    
    form = NominationForm()
    if request.method == 'POST':
        form = NominationForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('normapp')
    
    else:
        form = NominationForm()

    context = {
        'norm': norm,
        'form': form,
        'application': application,
        'approve': approve,
    }

    return render(request, 'admin/nominations.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_nomineeApproval(request, pk):
    nominee_id = get_object_or_404(Nominations, pk=pk)
    

    if request.method == 'POST':
        form = NominationApproval(request.POST, instance=nominee_id)
        if form.is_valid():
            form.save()
            url = reverse('nominee_approval', kwargs={'pk': nominee_id.pk})
            return redirect(url)
        
    else:
        form = NominationApproval(instance=nominee_id)
       
    
    context = {
        'nominee_id': nominee_id,
        'form': form,
    }

    return render(request, 'admin/nominee.html', context)


@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_event_profile(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    event = event_id.id
    report = PostEventReport.objects.filter(event_id=event)
    
    if request.method == 'POST':
        form = EventForm(request.POST, request.FILES, instance=event_id)
        form2 = ReportForm(request.POST)
        form3 = InvoiceForm(request.POST)
        if form.is_valid():
            form.save()
            url = reverse('event', kwargs={'pk': event_id.pk})
            return redirect(url)
        elif form2.is_valid():
            report_form, created = PostEventReport.objects.get_or_create(event_id=event_id.id, defaults=form2.cleaned_data)
            if not created:
                report_form.__dict__.update(form2.cleaned_data)
                report_form.save()
            url = reverse('event', kwargs={'pk': event_id.pk})
            messages.success(request, "Event has been successfully reported!")
            return redirect(url)
        if form3.is_valid():
            form3 = form3.save(commit=False)
            form3.application_id = event_id.id
            form3.save()
            url = reverse('event', kwargs={'pk': event_id.pk})
            return redirect(url)

    else:
        form = EventForm(instance=event_id)
        form2 = ReportForm()
        form3 = InvoiceForm()
    
    context = {
        'event_id': event_id,
        'form': form,
        'form2': form2,
        'form3': form3,
        'report': report.last(),
    }

    return render(request, 'admin/event_profile.html', context)

@login_required
@user_passes_test(is_admin, login_url='/login/', redirect_field_name='admin-dash')
def admin_announcement(request):
    users = CustomUser.objects.all()
    email_list = [user.email for user in users]

    announcement = COPEventAnnouncement.objects.all()

    form = AnnouncementForm()
    if request.method == 'POST':
        form = AnnouncementForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = form.cleaned_data['sender']

            from_email = 'no-reply@mhinnov8.com.ng'
            recipient_list = email_list
            send_mail(subject, message, from_email,  recipient_list, sender)

            form.save()
            return redirect('announcement')
    else:
        form = AnnouncementForm()

    context = {
        'form': form,
        'announcement': announcement,
    }

    return render(request, 'admin/announcement.html', context)


#COP Desk Officer
@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def cop_admin(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today)
    )
    
    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }

    return render(request, 'cop/dashboard.html', context)

@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def org(request):
    members = Organisation.objects.all()

    mda = Organisation.objects.filter(organisation_type='GO/MDAs').count()
    ngo = Organisation.objects.filter(organisation_type='NGO/iNGO').count()
    private = Organisation.objects.filter(organisation_type='private').count()
    youth = Organisation.objects.filter(organisation_type='Women/YouthLead').count()

    form = AddOrgForm()

    if request.method == "POST":
        form = AddOrgForm(request.POST)
        if form.is_valid():
            org_instance = form.save(commit=False)
            org_instance.role = 'Organisation'
            
            # Use Django's set_password method to securely set the password
            org_instance.set_password('Nccc@COP28')

            org_instance.save()

            try:
                # Assuming send_verification_email is a method in your Organisation model
                org_instance.send_verification_email(request)

                messages.success(
                    request, 'A verification email has been sent to the organisation.')
                return redirect('organisations')

            except Exception as e:
                messages.error(
                    request, f'There was an error sending the verification email: {e}')

    context = {
        'members': members,
        'mda': mda,
        'ngo': ngo,
        'youth': youth,
        'private': private,
        'form': form
    }

    return render(request, 'cop/organisations.html', context)

@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def org_prof(request, pk):
    member_id = get_object_or_404(Organisation, pk=pk)
    instance = Organisation.objects.get(pk=pk)

    if request.method == 'POST':
        form = StatusForm(request.POST, instance=instance)
        if form.is_valid():
            user = request.user
            form = form.save(commit=False)
            form.approved_by = user
            form.save()
            #url = reverse('org_prof', kwargs={'pk': member_id.pk})
            return redirect('organisations')
    else:
        form = StatusForm(instance=instance)
    context = {
        'member_id': member_id,
        'form': form,
        
    }

    return render(request, 'cop/org_profile.html', context)

@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def side_event(request):
    events = COPEventApplication.objects.all()
    application = COPEventApplication.objects.count()
    approve = COPEventApplication.objects.filter(status='Approved').count()
    hosted = PostEventReport.objects.count()

    form = EventForm()
    if request.method == 'POST':
        form = EventForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('side_event')
    
    else:
        form = EventForm()

    context = {
        'events': events,
        'form': form,
        'application': application,
        'approve': approve,
        'hosted': hosted,
    }

    return render(request, 'cop/side_event.html', context)

@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def normApp(request):
    norm = Nominations.objects.all()
    application = Nominations.objects.count()
    approve = Nominations.objects.filter(status='Approved').count()
    

    form = NominationForm()
    if request.method == 'POST':
        form = NominationForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('normapp')
    
    else:
        form = NominationForm()

    context = {
        'norm': norm,
        'form': form,
        'application': application,
        'approve': approve,
    }

    return render(request, 'cop/nominations.html', context)

@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def nomineeApproval(request, pk):
    nominee_id = get_object_or_404(Nominations, pk=pk)
    

    if request.method == 'POST':
        form = NominationApproval(request.POST, instance=nominee_id)
        if form.is_valid():
            form.save()
            url = reverse('nominee_approval', kwargs={'pk': nominee_id.pk})
            return redirect(url)
        
    else:
        form = NominationApproval(instance=nominee_id)
       
    
    context = {
        'nominee_id': nominee_id,
        'form': form,
    }

    return render(request, 'cop/nominee.html', context)


@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def event_profile(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    event = event_id.id
    report = PostEventReport.objects.filter(event_id=event)
    invoice = Invoice.objects.filter(application=event_id).first()

    if request.method == 'POST':
        form = EventForm(request.POST, request.FILES, instance=event_id)
        
        if form.is_valid():
            form.save()
            url = reverse('event', kwargs={'pk': event_id.pk})
            return redirect(url)
    else:
        form = EventForm(instance=event_id)
    
    context = {
        'event_id': event_id,
        'form': form,
        'report': report.last(),
        'payment_status': invoice.payment_status if invoice else 'Unpaid',
    }

    return render(request, 'cop/event_profile.html', context)


@login_required
@user_passes_test(is_cop_desk_officer, login_url='/login/', redirect_field_name='admin-cop')
def announcement(request):
    users = CustomUser.objects.all()
    email_list = [user.email for user in users]

    announcement = COPEventAnnouncement.objects.all()

    form = AnnouncementForm()
    if request.method == 'POST':
        form = AnnouncementForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            #sender = form.cleaned_data['sender']

            from_email = 'no-reply@mhinnov8.com.ng'
            recipient_list = email_list
            send_mail(subject, message, from_email,  recipient_list)

            form.save()
            return redirect('announcement')
    else:
        form = AnnouncementForm()

    context = {
        'form': form,
        'announcement': announcement,
    }

    return render(request, 'cop/announcement.html', context)



#Public Dashoard
def event_list(request):
    today = date.today()

    # Filter events with a start_time in the future
    event_list = COPEventApplication.objects.filter(day__gte=today, status='Approved')

    # Sort events by start_time
    event_list = event_list.order_by('day')

    context = {
        'event_list': event_list,
    }

    return render(request, 'event_list.html', context)

def event_view(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    
    context = {
        'event_id': event_id,
    }
    return render(request, 'event.html', context)

def report_list(request):
    report_list = PostEventReport.objects.order_by('-date_created')

    context = {
        'report_list': report_list
    }
    return render(request, 'report_list.html', context)

def report_view(request, pk):
    report_id = get_object_or_404(PostEventReport, pk=pk)
    
    context = {
        'report_id': report_id,
    }
    return render(request, 'report.html', context)

#Organisation Dashboard
@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def org_dashboard(request):
    user = request.user

    try:
        org = Organisation.objects.get(user=user)
    except Organisation.DoesNotExist:
        org = None

    approve = 0

    if org:
        events = COPEventApplication.objects.filter(org=org)
        approve = events.filter(status='Approved').count()
        hosted = PostEventReport.objects.filter(event__in=events, event__isnull=False).count()
        report = PostEventReport.objects.filter(event__in=events, event__isnull=False).order_by('-id')[:3]
        total_speakers = events.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
        host = 1
        session = PostEventReport.objects.filter(event__in=events, event__isnull=False).count()
        
        minutes = session * 45
        total_duration = minutes // 60
        minu = minutes % 60

        today = date.today()

        events_today = COPEventApplication.objects.filter(
            Q(day=today)
        )
    else:
        hosted = 0

    context = {
        'approve': approve,
        'hosted': hosted,
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'events_today': events,
        'minu': minu,
    }


    return render(request, 'organisation/dashboard.html', context)

@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def org_register(request):
    user = request.user  # Get the current user
    if request.method == 'POST':
        form = OrganisationForm(request.POST, request.FILES)
        if form.is_valid():
            form_instance = form.save(commit=False)
            form_instance.user = user
            form_instance.save()
            return redirect('org_dashbord')
    else:
        form = OrganisationForm()

    context = {
        'form': form,
    }

    return render(request, 'organisation/register.html', context)

@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def org_update(request):
    user = request.user  # Get the current user
    member_id = Organisation.objects.get(user=user)

    try:
        existing_data = Organisation.objects.get(user=user)
    except Organisation.DoesNotExist:
        existing_data = None

    if request.method == 'POST':
        form = OrganisationForm(request.POST, request.FILES)

        if form.is_valid():
            form_instance = form.save(commit=False)
            form_instance.user = user  # Set the user
            form_instance.id = existing_data.id 
            form_instance.date_created = existing_data.date_created
            form_instance.save()
            return redirect('org_update')
    else:
        form = OrganisationForm(instance=existing_data)  # Populate the form with existing data
    context = {
        'form': form,
        'member_id': member_id,
    }

    return render(request, 'organisation/profile.html', context)

@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def org_event(request):
    user = request.user

    try:
        org = Organisation.objects.get(user=user)
    except Organisation.DoesNotExist:
        org = None

    application = 0
    approve = 0

    if org:
        events = COPEventApplication.objects.filter(org=org)
        application = events.count()
        approve = events.filter(status='Approved').count()
        hosted = PostEventReport.objects.filter(event__in=events).count()
    else:
        hosted = 0

    form = OrgEventForm()
    
    if request.method == 'POST':
        form = OrgEventForm(request.POST, request.FILES)
        if form.is_valid():
            form = form.save(commit=False)
            form.org = org
            form.save()
            return redirect('org_event')
    
    else:
        form = OrgEventForm()

    context = {
        'events': events,
        'form': form,
        'application': application,
        'approve': approve,
        'hosted': hosted,
    }

    return render(request, 'organisation/side_event.html', context)

@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def normination(request):
    user = request.user

    try:
        org = Organisation.objects.get(user=user)
    except Organisation.DoesNotExist:
        org = None

    application = 0
    approve = 0
    norm = None

    if org:
        norm = Nominations.objects.filter(org=org)
        application = norm.count()
        approve = norm.filter(status='Approved').count()

    if request.method == 'POST':
        form = NominationForm(request.POST, request.FILES)
        
        if form.is_valid():
            email = form.cleaned_data['email']  # Get the email from the form

            try:
                user = CustomUser.objects.get(email=email)
            except CustomUser.DoesNotExist:
                # User with the provided email doesn't exist, create a new user
                name = form.cleaned_data['name']
                password = "Nccc@COP28"
                role = "Activist"
                user = CustomUser.objects.create_user(email=email, password=password, name=name, role=role)
                user.send_verification_email(request)

            form.instance.user = user  # Assign the user to the form
            form.instance.org = org  # Assign the organization to the form
            form.save()
            return redirect('normination')
        else:
            print(form.errors)
    else:
        form = NominationForm()

    context = {
        'form': form,
        'application': application,
        'approve': approve,
        'norm': norm
    }

    return render(request, 'organisation/accreditation.html', context)


@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def nominee(request, pk):
    nominee_id = get_object_or_404(Nominations, pk=pk)
    

    if request.method == 'POST':
        form = NominationForm(request.POST, request.FILES, instance=nominee_id)
        if form.is_valid():
            form.save()
            url = reverse('org_event_profile', kwargs={'pk': nominee_id.pk})
            return redirect(url)
        
    else:
        form = NominationForm(instance=nominee_id)
       
    
    context = {
        'nominee_id': nominee_id,
        'form': form,
    }

    return render(request, 'organisation/nominee.html', context)


@login_required
@user_passes_test(is_organisation, login_url='/login/', redirect_field_name='org_dashbord')
def org_event_profile(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    reources = get_object_or_404(EventResources, pk=pk)
    try:
        invoice = Invoice.objects.get(application_id=event_id)
    except Invoice.DoesNotExist:
        invoice = None

    if request.method == 'POST':
        form = ResourcesForm(request.POST, request.FILES)
        form2 = PaidForm(request.POST, request.FILES, instance=invoice)
        
        if form.is_valid():
            form = form.save(commit=False)
            form.resources = event_id
            form.save()
            url = reverse('org_event_profile', kwargs={'pk': event_id.pk})
            return redirect(url)
        elif form2.is_valid():
            form2.save()
            url = reverse('org_event_profile', kwargs={'pk': event_id.pk})
            return redirect(url)
    else:
        form = ResourcesForm(instance=event_id)
        # Get the associated invoice
        try:
            invoice = Invoice.objects.get(application_id=event_id)
        except Invoice.DoesNotExist:
            invoice = None

        form2 = PaidForm(instance=invoice)
    
    context = {
        'event_id': event_id,
        'resources': reources,
        'form': form,
        'form2': form2,
        'invoice': invoice,
    }

    return render(request, 'organisation/event_profile.html', context)

#Finance Dashboard
@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_dash(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today)
    )

    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }
    return render(request, 'finance/dashboard.html', context)

@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_side_event(request):
    events = COPEventApplication.objects.all()
    application = COPEventApplication.objects.count()
    invoice = Invoice.objects.count()
    invoices = Invoice.objects.all()
    new = application - invoice

    # Creating a dictionary to map event ids to their invoice status
    invoice_status = {invoice.application_id: True for invoice in invoices}

    for event in events:
        event.invoice_generated = invoice_status.get(event.id, False)

    context = {
        'events': events,
        'application': application,
        'invoice': invoice,
        'new': new,
    }

    return render(request, 'finance/side_event.html', context)

@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_invoice(request):
    invoices = Invoice.objects.all()
    paid = Invoice.objects.filter(payment_status='Paid')
    num_paid = paid.count
    pending = Invoice.objects.filter(payment_status='Unpaid').count()

    paid_amount = paid.aggregate(Sum('amount_paid'))['amount_paid__sum'] or 0

    context = {
        'invoices': invoices,
        'paid': num_paid,
        'pending': pending,
        'paid_amount': paid_amount
    }

    return render(request, 'finance/invoice_list.html', context)

@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_event_profile(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    event = event_id.id

    # Check if an invoice is already generated for this event
    invoice_exists = Invoice.objects.filter(application_id=event).exists()

    if request.method == 'POST':
        if not invoice_exists:
            form = InvoiceForm(request.POST)
            if form.is_valid():
                invoice = form.save(commit=False)
                invoice.application_id = event
                invoice.save()
                url = reverse('fin-side-event', kwargs={'pk': event_id.pk})
                return redirect(url)
    else:
        form = InvoiceForm()

    context = {
        'event_id': event_id,
        'form': form,
        'invoice_exists': invoice_exists,
    }

    return render(request, 'finance/event_profile.html', context)

@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_invoice_profile(request, pk):
    invoice_id = get_object_or_404(Invoice, pk=pk)

    form = ComfirmForm()
    if request.method == 'POST':
        form = ComfirmForm(request.POST, instance=invoice_id)
        
        if form.is_valid():
            form.save()
            url = reverse('fin-invoice-profile', kwargs={'pk': invoice_id.pk})
            return redirect(url)
    else:
        form = ComfirmForm()
        
    context = {
        'invoice_id': invoice_id,
        'form': form,
    }

    return render(request, 'finance/invoice.html', context)

@login_required
@user_passes_test(is_finance, login_url='/login/', redirect_field_name='fin-dash')
def fin_announcement(request):
    users = CustomUser.objects.all()
    email_list = [user.email for user in users]

    announcement = COPEventAnnouncement.objects.all()

    form = AnnouncementForm()
    if request.method == 'POST':
        form = AnnouncementForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            #sender = form.cleaned_data['sender']

            from_email = 'no-reply@mhinnov8.com.ng'
            recipient_list = email_list
            send_mail(subject, message, from_email,  recipient_list)

            form.save()
            return redirect('fin-announcement')
    else:
        form = AnnouncementForm()

    context = {
        'form': form,
        'announcement': announcement,
    }

    return render(request, 'finance/announcement.html', context)

#event Manager
@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_dash(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today)
    )

    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }
    return render(request, 'event/dashboard.html', context)

@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_side_event(request):
    events = COPEventApplication.objects.all().order_by('end_time')
    application = COPEventApplication.objects.count()
    report = PostEventReport.objects.count()
    reports = PostEventReport.objects.all()
    
    # Creating a dictionary to map event ids to their invoice status
    report_status = {report.event_id: True for report in reports}

    for event in events:
        event.event_reported = report_status.get(event.id, False)
    
    
   
    context = {
        'events': events,
        'application': application,
        'report': report,
    }

    return render(request, 'event/side_event.html', context)


@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_event_profile(request, pk):
    event_id = get_object_or_404(COPEventApplication, pk=pk)
    event = event_id.id

    # Check if an invoice is already generated for this event
    report_exists = PostEventReport.objects.filter(event_id=event).exists()

    if request.method == 'POST':
        if not report_exists:
            form = ReportForm(request.POST)
            if form.is_valid():
                report = form.save(commit=False)
                report.event_id = event
                report.save()
                url = reverse('event-event-profile', kwargs={'pk': event_id.pk})
                return redirect(url)
    else:
        form = ReportForm()

    context = {
        'event_id': event_id,
        'form': form,
        'report_exists': report_exists,
    }

    return render(request, 'event/event_profile.html', context)


@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_announcement(request):
    users = CustomUser.objects.all()
    email_list = [user.email for user in users]

    announcement = COPEventAnnouncement.objects.all()

    form = AnnouncementForm()
    if request.method == 'POST':
        form = AnnouncementForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            #sender = form.cleaned_data['sender']

            from_email = 'no-reply@mhinnov8.com.ng'
            recipient_list = email_list
            send_mail(subject, message, from_email,  recipient_list)

            form.save()
            return redirect('event-announcement')
    else:
        form = AnnouncementForm()

    context = {
        'form': form,
        'announcement': announcement,
    }

    return render(request, 'event/announcement.html', context)

@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_report_list(request):
    report_list = PostEventReport.objects.order_by('-date_created')

    context = {
        'report_list': report_list
    }
    return render(request, 'event/report_list.html', context)

@login_required
@user_passes_test(is_event_manager, login_url='/login/', redirect_field_name='event-dash')
def event_report_view(request, pk):
    report_id = get_object_or_404(PostEventReport, pk=pk)
    
    context = {
        'report_id': report_id,
    }
    return render(request, 'event/report.html', context)

#Bilaterals
@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_dash(request):
    event = COPEventApplication.objects.all()
    delegates = Nominations.objects.filter(status='Approved').count()
    organisations = Organisation.objects.count()
    side_events = COPEventApplication.objects.filter(status='Approved').count()
    
    report = PostEventReport.objects.filter(event__isnull=False).order_by('-id')[:3]
    total_speakers = COPEventApplication.objects.filter(posteventreport__isnull=False).aggregate(Sum('number_of_speakers'))['number_of_speakers__sum'] or 0
    host = COPEventApplication.objects.filter(posteventreport__isnull=False).values('org').annotate(Count('org')).count()
    session = PostEventReport.objects.filter(event__isnull=False).count()
    
    minutes = session * 45
    total_duration = minutes // 60
    minu = minutes % 60

    today = date.today()

    events_today = COPEventApplication.objects.filter(
        Q(day=today)
    )

    context = {
        'report': report,
        'session': session,
        'total_speakers': total_speakers,
        'total_duration': total_duration,
        'host': host,
        'delegates': delegates,
        'organisations': organisations,
        'side_events': side_events,
        'events_today': events_today,
        'minu': minu,
    }
    return render(request, 'bilateral/dashboard.html', context)

@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_meeting(request):
    all = Bilateral.objects.all()
    all_count = all.count()
    
    today = date.today()

    meeting_today = Bilateral.objects.filter(
        Q(date__date=today)
    )
    meeting_today_count = meeting_today.count()
    
    if request.method == 'POST':
        form = MeetingForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('bil-side-event')
    else:
        form = MeetingForm()
    
    
   
    context = {
        'all': all,
        'all_count': all_count,
        'meeting_today': meeting_today,
        'meeting_today_count': meeting_today_count,
        'form': form,
    }

    return render(request, 'bilateral/side_event.html', context)

@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_meeting_list(request):
    all = Bilateral.objects.all()
    
    if request.method == 'POST':
        form = MeetingForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('bil-meeting-list')
    else:
        form = MeetingForm()
    
    
   
    context = {
        'all': all,
        'form': form,
    }

    return render(request, 'bilateral/meeting_list.html', context)

@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_meeting_profile(request, pk):
    meeting_id = get_object_or_404(Bilateral, pk=pk)
    meeting = meeting_id.id

    # Check if an invoice is already generated for this event
    report_exists = BilateralReport.objects.filter(meeting_id=meeting).exists()

    if request.method == 'POST':
        if not report_exists:
            form = ReportMeetingForm(request.POST)
            if form.is_valid():
                report = form.save(commit=False)
                report.meeting_id = meeting
                report.save()
                url = reverse('bil-event-profile', kwargs={'pk': meeting_id.pk})
                return redirect(url)
    else:
        form = ReportMeetingForm()

    context = {
        'meeting_id': meeting_id,
        'form': form,
        'report_exists': report_exists,
    }

    return render(request, 'bilateral/event_profile.html', context)

@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_report_list(request):
    report_list = BilateralReport.objects.order_by('-date_created')

    context = {
        'report_list': report_list
    }
    return render(request, 'bilateral/report_list.html', context)

@login_required
@user_passes_test(is_bilaterals, login_url='/login/', redirect_field_name='bil-dash')
def bil_report_view(request, pk):
    report_id = get_object_or_404(BilateralReport, pk=pk)
    
    context = {
        'report_id': report_id,
    }
    return render(request, 'bilateral/report.html', context)

#Individual
@login_required
@user_passes_test(is_individual, login_url='/login/', redirect_field_name='indi-dash')
def activist_dashboard(request):

    context = {

    }

    return render(request, 'activist/dashboard.html', context)


EVENT_DAYS = [
    ('2024-11-13', 'November 13'),
    ('2024-11-14', 'November 14'),
    ('2024-11-15', 'November 15'),
    ('2024-11-16', 'November 16'),
    ('2024-11-17', 'November 17'),
    ('2024-11-18', 'November 18'),
    ('2024-11-19', 'November 19'),
    ('2024-11-20', 'November 20'),
    ('2024-11-21', 'November 21')
]

def generate_time_slots(start_time, end_time, display_interval, actual_interval):
    time_slots = []
    current_time = start_time
    while current_time < end_time:
        display_end_interval = (datetime.combine(datetime.today(), current_time) + display_interval).time()
        actual_end_interval = (datetime.combine(datetime.today(), current_time) + actual_interval).time()
        time_slots.append((current_time.strftime("%H:%M:%S"), f"{current_time.strftime('%I:%M %p')} - {display_end_interval.strftime('%I:%M %p')}"))
        current_time = actual_end_interval
    return time_slots

TIME_SLOTS = generate_time_slots(time(9, 0), time(18, 0), timedelta(minutes=45), timedelta(hours=1))


def calendar_view(request):
    events = COPEventApplication.objects.all()
    
    events_by_day_and_time = {}
    
    for event in events:
        key = f"{event.day.strftime('%Y-%m-%d')}_{event.time.strftime('%H:%M:%S')}"
        events_by_day_and_time[key] = event.status

    context = {
        'EVENT_DAYS': EVENT_DAYS,
        'TIME_SLOTS': TIME_SLOTS,
        'events_by_day_and_time': events_by_day_and_time,
    }
    
    return render(request, 'calendar.html', context)

def attendance(request):
    if request.method == 'POST':
        form = AttendaneForm(request.POST)
        if form.is_valid():
            form.save()
            
            return redirect('thank_you')
    else:
        form = AttendaneForm()

    context = {'form': form}
    return render(request, 'attendance.html', context)

def thank_you(request):
    return render(request, 'thank_you.html')

def attendance_view(request):
    list = Attendane.objects.all().order_by('name')
    counts = list.count()
    badge_type = request.GET.get('badge_type')
    negotiation_track = request.GET.get('negotiation_track')

    if badge_type:
        list = list.filter(badge_type=badge_type)

    if negotiation_track:
        list = list.filter(negotiation_track=negotiation_track)
    
    context = {
        'list': list,
        'counts': counts,
        'type_choices': Attendane.TYPE_CHOICES,
        'track_choices': Attendane.TRACK_CHOICES,
    }
    return render(request, 'admin/attendance.html', context)
