import logging
from datetime import timedelta
from unicodedata import category

from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import RedirectView, TemplateView
from django.shortcuts import get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin

from core.mailer import Emailer
from core.utils import generate_random_string
from events.forms import RegistrationForm, EmailForm, PresentRegistrationForm
from events.models import Registration, Event, Category
from users.models import ConfirmationCode, SecurityCode
from core.views import DefaultContextMixin

logger = logging.getLogger(__name__)


class RegistrationView(RedirectView):
    success_url = reverse_lazy('index')

    def post(self, request, *args, **kwargs):
        # get event by pk
        event = get_object_or_404(Event, pk=kwargs['pk'])

        # handle registration form
        form = RegistrationForm(request.POST)
        if form.is_valid():
            if event.registrations_require_confirmation:
                # create email security code for feature requests
                security_code, created = SecurityCode.objects.get_or_create(email=form.cleaned_data['email'])

            try:
                reg_category = Category.objects.get(name=form.cleaned_data['category'])
            except Category.DoesNotExist:
                reg_category = None

            try:
                # create a new Registration
                registration = Registration(
                    event=event,
                    first_name=form.cleaned_data['first_name'],
                    last_name=form.cleaned_data['last_name'],
                    nick_name=form.cleaned_data['nick_name'],
                    phone=form.cleaned_data['phone'],
                    email=form.cleaned_data['email'],
                    text=form.cleaned_data['text'],
                    category=form.cleaned_data['category'],
                    category_object=reg_category,
                )
                registration.save()

                # skip confirmation when event does not require it
                if not event.registrations_require_confirmation:
                    registration.is_confirmed = True
                    registration.variable_symbol = f'{event.variable_symbol_prefix}-{registration.id}'
                    registration.save()
                    messages.success(request, _('Registration successful.'))

                    # send email with information about registration
                    emailer = Emailer()

                    # prepare url for registration detail
                    url = f'{settings.PUBLIC_URL}{reverse_lazy(
                        "my_registrations_list",
                        kwargs={
                            "uid": event.uid,
                            "email": form.cleaned_data["email"],
                            "security_code": security_code.code
                        })}'

                    # send email
                    emailer.send(
                        template_name='registration_info',
                        recipient=form.cleaned_data['email'],
                        subject=f'Registrace na zavod {event.name}',
                        context_dict={
                            'name': event.name,
                            'date': event.start,
                            "url": url,
                        },
                    )

                    # redirect to registrations list
                    return HttpResponseRedirect(reverse_lazy('my_registrations_list', kwargs={
                        "uid": event.uid,
                        "email": form.cleaned_data["email"],
                        "security_code": security_code.code
                    }))

                # create confirm code
                confirmation_code = ConfirmationCode(
                    email=form.cleaned_data['email'],
                    registration_id=registration.id,
                    code=f'{generate_random_string(16)}-{registration.created.timestamp()}',
                )
                confirmation_code.save()

                # send email with confirmation link
                emailer = Emailer()
                emailer.send(
                    template_name='registration',
                    recipient=form.cleaned_data['email'],
                    subject='Registrace na zavod Kalske Borec 2025',
                    context_dict={
                        'name': event.name,
                        'date': event.start,
                        'email': form.cleaned_data['email'],
                        'nick_name': form.cleaned_data['nick_name'],
                        'phone': form.cleaned_data['phone'],
                        'racer': f'{form.cleaned_data["first_name"]} {form.cleaned_data["last_name"]}',
                        'category': form.cleaned_data['category'],
                        'text': form.cleaned_data['text'],
                        'security_code': security_code.code,
                        "url": f'{settings.PUBLIC_URL}/events/confirm-registration/?email={form.cleaned_data['email']}&r={registration.id}&code={confirmation_code.code}&security_code={security_code.code}',
                    },
                )

                messages.success(request, _('Registration successful.'))
            except Exception as e:
                logger.error(e)
                messages.error(request, _('Registration failed.'))

        else:
            messages.error(request, _('Please correct the error below.'))

        return HttpResponseRedirect(self.success_url)


class ConfirmRegistrationView(RedirectView):
    success_url = reverse_lazy('index')

    def get(self, request, *args, **kwargs):
        code = request.GET.get('code')
        email = request.GET.get('email')
        registration_id = request.GET.get('r')

        # if not all params are present
        if not code or not email or not registration_id:
            messages.error(request, _('Invalid confirmation link.'))
            return HttpResponseRedirect(self.success_url)

        try:
            # get confirmation code
            confirmation = ConfirmationCode.objects.get(
                email=email,
                code=code,
                registration_id=registration_id
            )

            messages.success(request, _('Registration completed.'))

            # get and confirm registration and assign user
            registration = Registration.objects.get(pk=registration_id)
            registration.is_confirmed = True
            registration.variable_symbol = f'{registration.event.variable_symbol_prefix}-{registration.id}'
            registration.save()

            # delete confirmation code
            confirmation.delete()

            # get security code for email
            security_code = SecurityCode.objects.get(email=email)

            # redirect to registrations list
            return HttpResponseRedirect(reverse_lazy('my_registrations_list', kwargs={
                "uid": registration.event.uid,
                "email": registration.email,
                "security_code": security_code.code
            }))

        except Exception as e:
            logger.error(e)
            messages.error(request, _('Invalid confirmation link.'))
            return HttpResponseRedirect(self.success_url)


class MyRegistrationsRequestView(RedirectView):
    success_url = reverse_lazy('index')

    def post(self, request, *args, **kwargs):
        event = get_object_or_404(Event, pk=kwargs['pk'])

        form = EmailForm(request.POST)
        if form.is_valid():
            try:
                # get security code
                security_code = SecurityCode.objects.get(email=form.cleaned_data['email'])
                # send email with confirmation link
                emailer = Emailer()
                # prepare url for registration detail
                url = f'{settings.PUBLIC_URL}{reverse_lazy(
                    "my_registrations_list",
                    kwargs={
                        "uid": event.uid,
                        "email": form.cleaned_data["email"],
                        "security_code": security_code.code
                    })}'

                emailer.send(
                    template_name='my_registrations_request',
                    recipient=form.cleaned_data['email'],
                    subject='Moje registrace na zavod Kalske Borec 2025',
                    context_dict={
                        'name': event.name,
                        'date': event.start,
                        'url': url,
                    },
                )

                messages.success(request, _('Request sending successful.'))
            except Exception as e:
                logger.error(e)
                messages.error(request, "Pro zadanej email neexistuje žádná registrace.")

        else:
            messages.error(request, _('Please correct the error below.'))

        return HttpResponseRedirect(self.success_url)


class MyRegistrationsListView(DefaultContextMixin, TemplateView):
    template_name = 'events/my_registrations.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # check security code if user is not admin
        if not self.request.user.is_superuser:
            security_code = get_object_or_404(SecurityCode, email=kwargs['email'])
            if security_code.code != kwargs['security_code']:
                messages.error(self.request, _('Invalid security code.'))
                return context

        context['registrations'] = Registration.objects.filter(email=kwargs['email'])

        return context


class RegistrationsListViews(LoginRequiredMixin, DefaultContextMixin, TemplateView):
    template_name = 'events/registrations_list.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['registrations'] = context['event'].registrations.all().order_by('category')
        return context


class RegistrationPresentView(LoginRequiredMixin, DefaultContextMixin, TemplateView):
    template_name = 'events/presentation_confirm.html'
    success_url = reverse_lazy('registrations_presentation')

    def get(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        context['registration'] = get_object_or_404(Registration, pk=kwargs['pk'])
        context['form'] = PresentRegistrationForm(instance=context['registration'])

        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        registration = get_object_or_404(Registration, pk=kwargs['pk'])
        form = PresentRegistrationForm(request.POST, instance=registration)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.is_presented = True
            instance.save()
            messages.success(request, _('Prezentovano'))
            return HttpResponseRedirect(self.success_url)
        else:
            messages.error(request, _('Please correct the error below.'))
            return self.get(request, *args, **kwargs)


class ResultsView(DefaultContextMixin, TemplateView):
    template_name = 'events/results.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        context['category'] = get_object_or_404(Category, pk=kwargs['pk'])
        context['finished'] = []
        context['unfinished'] = []
        for registration in context['category'].registrations.all():
            if registration.is_ended:
                context['finished'].append({
                    'registration': registration,
                    'duration': registration.total_duration,
                })
            else:
                context['unfinished'].append(registration)

        # sort by duration
        context['finished'] = sorted(context['finished'], key=lambda x: x['duration'])

        # add rank
        rank = 0
        last_duration = timedelta(0)
        for registration in context['finished']:
            if registration['duration'] != last_duration:
                rank += 1
            registration['rank'] = rank



        return context