# Copyright (C) 2020 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later

from django import forms
from django.conf import settings
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.forms import FileInput
from django.utils.translation import gettext_lazy as _

from .models import CoachRegistration, ParticipantRegistration, Payment, \
    StudentRegistration, VolunteerRegistration


class SignupForm(UserCreationForm):
    """
    Signup form to registers participants and coaches
    They can choose the role at the registration.
    """

    role = forms.ChoiceField(
        label=lambda: _("role").capitalize(),
        choices=lambda: [
            ("participant", _("participant").capitalize()),
            ("coach", _("coach").capitalize()),
        ],
    )

    def clean_email(self):
        """
        Ensure that the email address is unique.
        """
        email = self.data["email"]
        if User.objects.filter(email=email).exists():
            self.add_error("email", _("This email address is already used."))
        return email

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["first_name"].required = True
        self.fields["last_name"].required = True
        self.fields["email"].required = True

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email', 'password1', 'password2', 'role',)


class AddOrganizerForm(forms.ModelForm):
    """
    Signup form to registers volunteers
    """

    def clean_email(self):
        """
        Ensure that the email address is unique.
        """
        email = self.data["email"]
        if User.objects.filter(email=email).exists():
            self.add_error("email", _("This email address is already used."))
        return email

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["first_name"].required = True
        self.fields["last_name"].required = True
        self.fields["email"].required = True

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email',)


class UserForm(forms.ModelForm):
    """
    Replace the default user form to require the first name, last name and the email.
    The username is always equal to the email.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["first_name"].required = True
        self.fields["last_name"].required = True
        self.fields["email"].required = True

    def clean_email(self):
        """
        Ensure that the email address is unique.
        """
        email = self.data["email"]
        if User.objects.filter(email=email).exclude(pk=self.instance.pk).exists():
            self.add_error("email", _("This email address is already used."))
        return email

    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email',)


class StudentRegistrationForm(forms.ModelForm):
    """
    A student can update its class, its school and if it allows Animath to contact him/her later.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["birth_date"].widget = forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d')
        if not settings.SUGGEST_ANIMATH:
            del self.fields["give_contact_to_animath"]

    class Meta:
        model = StudentRegistration
        fields = ('team', 'student_class', 'birth_date', 'gender', 'address', 'zip_code', 'city', 'country',
                  'phone_number', 'school', 'health_issues', 'housing_constraints',
                  'responsible_name', 'responsible_phone', 'responsible_email', 'give_contact_to_animath',
                  'email_confirmed',)


class PhotoAuthorizationForm(forms.ModelForm):
    """
    Form to send a photo authorization.
    """
    def clean_photo_authorization(self):
        if "photo_authorization" in self.files:
            file = self.files["photo_authorization"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["photo_authorization"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["photo_authorization"].widget = FileInput()

    class Meta:
        model = ParticipantRegistration
        fields = ('photo_authorization',)


class PhotoAuthorizationFinalForm(forms.ModelForm):
    """
    Form to send a photo authorization.
    """
    def clean_photo_authorization_final(self):
        if "photo_authorization_final" in self.files:
            file = self.files["photo_authorization_final"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["photo_authorization_final"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["photo_authorization_final"].widget = FileInput()

    class Meta:
        model = ParticipantRegistration
        fields = ('photo_authorization_final',)


class HealthSheetForm(forms.ModelForm):
    """
    Form to send a health sheet.
    """
    def clean_health_sheet(self):
        if "health_sheet" in self.files:
            file = self.files["health_sheet"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["health_sheet"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["health_sheet"].widget = FileInput()

    class Meta:
        model = StudentRegistration
        fields = ('health_sheet',)


class VaccineSheetForm(forms.ModelForm):
    """
    Form to send a vaccine sheet.
    """
    def clean_vaccine_sheet(self):
        if "vaccine_sheet" in self.files:
            file = self.files["vaccine_sheet"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["vaccine_sheet"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["vaccine_sheet"].widget = FileInput()

    class Meta:
        model = StudentRegistration
        fields = ('vaccine_sheet',)


class ParentalAuthorizationForm(forms.ModelForm):
    """
    Form to send a parental authorization.
    """
    def clean_parental_authorization(self):
        if "parental_authorization" in self.files:
            file = self.files["parental_authorization"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["parental_authorization"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["parental_authorization"].widget = FileInput()

    class Meta:
        model = StudentRegistration
        fields = ('parental_authorization',)


class ParentalAuthorizationFinalForm(forms.ModelForm):
    """
    Form to send a parental authorization.
    """
    def clean_parental_authorization(self):
        if "parental_authorization_final" in self.files:
            file = self.files["parental_authorization_final"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["parental_authorization"]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["parental_authorization_final"].widget = FileInput()

    class Meta:
        model = StudentRegistration
        fields = ('parental_authorization_final',)


class CoachRegistrationForm(forms.ModelForm):
    """
    A coach can tell its professional activity.
    """
    ACCOMPANYING_CONFIRM_CHOICES = [
        ("presence", _("I undertake to be present throughout the entire tournament weekend alongside the team (including overnight stays).")),
        ("rules", _("I undertake to respond to the team's (non-mathematical) problems and not to hesitate to discuss them with the tournament "
                    "organisers, who will be able to help.")),
        ("cancelling", _("In case of absence, I undertake to notify the organisers as soon as possible, providing a replacement if possible.")),
    ]

    confirm_accompanying = forms.MultipleChoiceField(
        required=False,
        widget=forms.CheckboxSelectMultiple,
        choices=ACCOMPANYING_CONFIRM_CHOICES,
        label=_("Responsabilities of accompanying coaches")
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not settings.SUGGEST_ANIMATH:
            del self.fields["give_contact_to_animath"]

    class Meta:
        model = CoachRegistration
        fields = ('team', 'is_scientific_coach', 'is_accompanying_coach', 'confirm_accompanying', 'gender', 'address',
                  'zip_code', 'city', 'country', 'phone_number', 'last_degree', 'professional_activity', 'health_issues',
                  'housing_constraints', 'give_contact_to_animath', 'email_confirmed')

    def clean(self):
        cleaned = super().clean()
        if cleaned.get("is_accompanying_coach"):
            selected = set(cleaned.get("confirm_accompanying") or [])
            required = {key for key, _ in self.ACCOMPANYING_CONFIRM_CHOICES}
            if selected != required:
                self.add_error(
                    "confirm_accompanying",
                    _("Please tick all the required confirmations."),
                )
        return cleaned


class VolunteerRegistrationForm(forms.ModelForm):
    """
    A volunteer can also tell its professional activity.
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if not settings.SUGGEST_ANIMATH:
            del self.fields["give_contact_to_animath"]

    class Meta:
        model = VolunteerRegistration
        fields = ('professional_activity', 'admin', 'give_contact_to_animath', 'email_confirmed',)


class PaymentAdminForm(forms.ModelForm):
    """
    Indicate payment information
    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["valid"].widget.choices[0] = ('unknown', _("Pending"))
        payment_type = kwargs.get('data', {}).get('type', "")
        self.fields['receipt'].required = payment_type in ["scholarship", "bank_transfer"]
        self.fields['additional_information'].required = payment_type in ["other"]

    def clean_receipt(self):
        if "receipt" in self.files:
            file = self.files["receipt"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["receipt"]

    def clean(self):
        cleaned_data = super().clean()

        if "type" in cleaned_data and cleaned_data['type'] in ["scholarship", "bank_transfer"] \
                and "receipt" not in self.files and not self.instance.receipt:
            self.add_error("receipt", _("You must upload your receipt."))

        return cleaned_data

    class Meta:
        model = Payment
        fields = ('type', 'receipt', 'additional_information', 'valid',)


class PaymentForm(forms.ModelForm):
    """
    Indicate payment information
    """
    def __init__(self, payment_type, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['type'].widget = forms.HiddenInput(attrs={'value': payment_type})
        self.fields['receipt'].required = payment_type in ["scholarship", "bank_transfer"]
        self.fields['additional_information'].required = payment_type in ["other"]

    def clean_receipt(self):
        if "receipt" in self.files:
            file = self.files["receipt"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]:
                raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file."))
            return self.cleaned_data["receipt"]

    def clean(self):
        cleaned_data = super().clean()

        if "type" in cleaned_data and cleaned_data['type'] in ["scholarship", "bank_transfer"] \
                and "receipt" not in self.files and not self.instance.receipt:
            self.add_error("receipt", _("You must upload your receipt."))

        return cleaned_data

    class Meta:
        model = Payment
        fields = ('type', 'receipt', 'additional_information',)
