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

import re

from bootstrap_datepicker_plus import DatePickerInput, DateTimePickerInput
from django import forms
from django.core.exceptions import ValidationError
from django.utils import formats
from django.utils.translation import gettext_lazy as _
from PyPDF3 import PdfFileReader

from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament


class TeamForm(forms.ModelForm):
    """
    Form to create a team, with the name and the trigram,...
    """
    def clean_trigram(self):
        trigram = self.cleaned_data["trigram"].upper()
        if not re.match("[A-Z]{3}", trigram):
            raise ValidationError(_("The trigram must be composed of three uppercase letters."))
        return trigram

    class Meta:
        model = Team
        fields = ('name', 'trigram',)


class JoinTeamForm(forms.ModelForm):
    """
    Form to join a team by the access code.
    """
    def clean_access_code(self):
        access_code = self.cleaned_data["access_code"]
        if not Team.objects.filter(access_code=access_code).exists():
            raise ValidationError(_("No team was found with this access code."))
        return access_code

    def clean(self):
        cleaned_data = super().clean()
        if "access_code" in cleaned_data:
            team = Team.objects.get(access_code=cleaned_data["access_code"])
            self.instance = team
        return cleaned_data

    class Meta:
        model = Team
        fields = ('access_code',)


class ParticipationForm(forms.ModelForm):
    """
    Form to update the problem of a team participation.
    """
    class Meta:
        model = Participation
        fields = ('tournament',)


class MotivationLetterForm(forms.ModelForm):
    def clean_file(self):
        if "motivation_letter" in self.files:
            file = self.files["motivation_letter"]
            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["motivation_letter"]

    class Meta:
        model = Team
        fields = ('motivation_letter',)


class RequestValidationForm(forms.Form):
    """
    Form to ask about validation.
    """
    _form_type = forms.CharField(
        initial="RequestValidationForm",
        widget=forms.HiddenInput(),
    )

    engagement = forms.BooleanField(
        label=_("I engage myself to participate to the whole TFJM²."),
        required=True,
    )


class ValidateParticipationForm(forms.Form):
    """
    Form to let administrators to accept or refuse a team.
    """
    _form_type = forms.CharField(
        initial="ValidateParticipationForm",
        widget=forms.HiddenInput(),
    )

    message = forms.CharField(
        label=_("Message to address to the team:"),
        widget=forms.Textarea(),
    )


class TournamentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.fields["date_start"].widget = DatePickerInput(
                format=formats.get_format_lazy(format_type="DATE_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["date_end"].widget = DatePickerInput(
                format=formats.get_format_lazy(format_type="DATE_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["inscription_limit"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["solution_limit"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["solutions_draw"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["syntheses_first_phase_limit"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["solutions_available_second_phase"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["syntheses_second_phase_limit"].widget = DateTimePickerInput(
                format=formats.get_format_lazy(format_type="DATETIME_INPUT_FORMATS", use_l10n=True)[0])
        self.fields["organizers"].widget = forms.CheckboxSelectMultiple()

    class Meta:
        model = Tournament
        fields = '__all__'


class SolutionForm(forms.ModelForm):
    def clean_file(self):
        if "file" in self.files:
            file = self.files["file"]
            if file.size > 5e6:
                raise ValidationError(_("The uploaded file size must be under 5 Mo."))
            if file.content_type != "application/pdf":
                raise ValidationError(_("The uploaded file must be a PDF file."))
            pdf_reader = PdfFileReader(file)
            pages = len(pdf_reader.pages)
            if pages > 30:
                raise ValidationError(_("The PDF file must not have more than 30 pages."))
            return self.cleaned_data["photo_authorization"]

    def save(self, commit=True):
        """
        Don't save a solution with this way. Use a view instead
        """

    class Meta:
        model = Solution
        fields = ('problem', 'file',)


class PoolForm(forms.ModelForm):
    class Meta:
        model = Pool
        fields = ('tournament', 'round', 'bbb_url', 'juries',)
        widgets = {
            "juries": forms.CheckboxSelectMultiple,
        }


class PoolTeamsForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields["participations"].queryset = self.instance.tournament.participations.all()

    class Meta:
        model = Pool
        fields = ('participations',)
        widgets = {
            "participations": forms.CheckboxSelectMultiple,
        }


class PassageForm(forms.ModelForm):
    def clean(self):
        cleaned_data = super().clean()
        if "defender" in cleaned_data and "opponent" in cleaned_data and "reporter" in cleaned_data \
                and len({cleaned_data["defender"], cleaned_data["opponent"], cleaned_data["reporter"]}) < 3:
            self.add_error(None, _("The defender, the opponent and the reporter must be different."))
        if "defender" in self.cleaned_data and "solution_number" in self.cleaned_data \
                and not Solution.objects.filter(participation=cleaned_data["defender"],
                                                problem=cleaned_data["solution_number"]).exists():
            self.add_error("solution_number", _("This defender did not work on this problem."))
        return cleaned_data

    class Meta:
        model = Passage
        fields = ('solution_number', 'place', 'defender', 'opponent', 'reporter',)


class SynthesisForm(forms.ModelForm):
    def clean_file(self):
        if "file" in self.files:
            file = self.files["file"]
            if file.size > 2e6:
                raise ValidationError(_("The uploaded file size must be under 2 Mo."))
            if file.content_type != "application/pdf":
                raise ValidationError(_("The uploaded file must be a PDF file."))
            return self.cleaned_data["photo_authorization"]

    def save(self, commit=True):
        """
        Don't save a synthesis with this way. Use a view instead
        """

    class Meta:
        model = Synthesis
        fields = ('type', 'file',)


class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ('defender_writing', 'defender_oral', 'opponent_writing',
                  'opponent_oral', 'reporter_writing', 'reporter_oral', )
