"""Visits admin panel configuration."""

from django import forms
from django.contrib import admin, messages
from django.template.defaultfilters import pluralize
from django.urls import reverse
from django.utils.safestring import mark_safe
from django.http import HttpResponse
import csv
from .models import Participation, Place, Visit
from profiles.models import Student
from users.models import User
import codecs

# Register your models here.


class SchoolFilter(admin.SimpleListFilter):
    title = 'établissement'
    parameter_name = 'profiles__school'

    def lookups(self, request, model_admin):
        list_of_school = []
        query = Student.objects.values_list(
            "school", flat=True).distinct()
        for school in query:
            list_of_school.append((school, school))
        return list_of_school

    def queryset(self, request, queryset):
        if self.value():
            emails = Student.objects.filter(
                school=self.value()).values_list("user__email", flat=True)
            return queryset.filter(user__email__in=emails)


class RegistrationsOpenFilter(admin.SimpleListFilter):
    """Custom filter to filter visits by their registration openness.

    In Django docs:
    https://docs.djangoproject.com/fr/2.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
    """

    title = 'état des inscriptions'
    parameter_name = 'registrations_open'

    def lookups(self, request, model_admin):
        yield (False, 'Fermées')
        yield (True, 'Ouvertes')

    def queryset(self, request, queryset):
        registrations_open = self.value()
        if registrations_open is None:
            return queryset
        return queryset.registrations_open(state=registrations_open)

    def value(self):
        """Convert the querystring value to a nullable boolean."""
        value = super().value()
        return {None: None, 'True': True, 'False': False}[value]


class VisitForm(forms.ModelForm):
    """Custom admin form for Visit."""

    class Meta:  # noqa
        model = Visit
        fields = '__all__'

    def clean(self):
        """Validate dates and time.

        - Deadline must be before the date
        - End time must be after start time

        Keep in mind that values may be `None` if not provided in the form.
        """
        cleaned_data = super().clean()
        date = cleaned_data.get('date')
        deadline = cleaned_data.get('deadline')
        start_time = cleaned_data.get('start_time')
        end_time = cleaned_data.get('end_time')
        if deadline is not None:
            if deadline.date() >= date:
                error = forms.ValidationError(
                    "La date limite d'inscription doit être avant la "
                    "date de la sortie."
                )
                self.add_error('deadline', error)
        if end_time is not None and start_time is not None:
            if end_time <= start_time:
                error = forms.ValidationError(
                    "L'heure de fin doit être après l'heure de début.")
                self.add_error('start_time', error)
                self.add_error('end_time', error)


class ParticipationInline(admin.TabularInline):
    """Inline for Participation."""
    # template = "visits/visit_tabular.md"
    actions = ["export_as_csv"]
    model = Visit.participants.through
    extra = 0
    fields = ('name', 'school', 'user', 'submitted', 'present')
    readonly_fields = ('name', 'school', 'user', 'submitted')

    def school(self, participation: Participation):
        """Return a link to the participation's user's school."""
        school = Student.objects.get(user=participation.user).school
        return school
    school.short_description = "Établissement"


    def name(self, participation: Participation):
        """Returns the participation's user's name"""
        return participation.user.first_name + " " + participation.user.last_name
    name.short_description = "Nom"

    class Media:
        css = {"all": ("css/hide_admin_original.css",)}


def accept_selected_participations(modeladmin, request, queryset):
    """Accept selected participations in list view."""
    for obj in queryset:
        obj.accepted = True
        obj.save()
    count = queryset.count()
    s = pluralize(count)
    messages.add_message(request, messages.SUCCESS,
                         f'{count} participation{s} acceptée{s} avec succès.')


accept_selected_participations.short_description = (
    'Accepter les participations sélectionnées')


def reject_selected_participations(modeladmin, request, queryset):
    """Reject selected participations in list view."""
    for obj in queryset:
        obj.accepted = False
        obj.save()
    count = queryset.count()
    s = pluralize(count)
    messages.add_message(request, messages.SUCCESS,
                         f'{count} participation{s} acceptée{s} avec succès.')


reject_selected_participations.short_description = (
    'Rejeter les participations sélectionnées')


@admin.register(Participation)
class ParticipationAdmin(admin.ModelAdmin):
    """Admin panel for visit participations."""

    list_display = ('submitted', 'visit', 'user_link', 'accepted', 'present')
    list_filter = (SchoolFilter, 'submitted', 'accepted', 'present')
    actions = [accept_selected_participations, reject_selected_participations]

    def user_link(self, participation: Participation):
        """Return a link to the participation's user."""
        url = reverse("admin:users_user_change", args=[participation.user.id])
        link = f'<a href="{url}">{participation.user}</a>'
        return mark_safe(link)

    user_link.short_description = 'Utilisateur'

    actions = ["export_as_csv"]

    def school(self, participation: Participation):
        """Return a link to the participation's user's school."""
        school = Student.objects.get(user=participation.user).school
        return school
    school.short_description = "Établissement"

    def export_as_csv(self, request, queryset):
        meta = self.model._meta
        field_names = [field.name for field in meta.fields]
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename={}.csv'.format(
            meta)
        response.write(codecs.BOM_UTF8)  # force response to be UTF-8
        writer = csv.writer(response, delimiter=';')

        writer.writerow(['first_name', 'last_name', 'school', 'grade',
                         'phone_number', 'scholarship'] + field_names)

        list_email = queryset.values_list("user__email", flat=True)
        nb_user = 0
        for obj in queryset:

            name = User.objects.filter(
                email=str(list_email[nb_user])).values('first_name', 'last_name', 'phone_number')
            school = Student.objects.filter(
                user__email=str(list_email[nb_user])).values('school', 'grade', 'scholarship')

            row = writer.writerow([name[0]['first_name'], name[0]['last_name'], school[0]['school'], school[0]['grade'], name[0]['phone_number'], school[0]['scholarship']] + [getattr(obj, field)
                                                                                                                                                                               for field in field_names])

            nb_user += 1
        return response

    export_as_csv.short_description = "Exporter sélection (en .csv)"


@ admin.register(Visit.organizers.through)
class VisitOrganizersAdmin(admin.ModelAdmin):
    """Admin panel for visit organizers."""

    list_display = ('visit', 'tutor',)


class OrganizersInline(admin.TabularInline):
    """Inline for visit organizers."""

    model = Visit.organizers.through
    extra = 0


@ admin.register(Visit)
class VisitAdmin(admin.ModelAdmin):
    """Admin panel for visits."""

    # IDEA create a dashboard using:
    # https://medium.com/@hakibenita/how-to-turn-django-admin-into-a-lightweight-dashboard-a0e0bbf609ad

    form = VisitForm
    inlines = (OrganizersInline, ParticipationInline,)
    list_display = ('__str__', 'place', 'date', 'start_time', 'deadline',
                    '_registrations_open', 'num_participants')
    list_filter = ('date', RegistrationsOpenFilter)
    search_fields = ('title', 'place',)
    exclude = ('participants', 'organizers',)

    def num_participants(self, obj):
        return obj.participants.count()
    num_participants.short_description = 'Participants'


@ admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
    """Admin panel for places."""

    list_display = ('name', 'address', 'num_visits', 'last_visit')
    list_display_links = ('name', 'last_visit')

    def num_visits(self, obj):
        return obj.visit_set.count()
    num_visits.short_description = 'Nombre de sorties'

    def last_visit(self, obj):
        return obj.visit_set.passed().order_by('date').first()
    last_visit.short_description = 'Dernière sortie'