"""This module holds the forms for the ``workshops`` app"""

from django import forms
from django.forms.models import inlineformset_factory
from django.utils.translation import ugettext_lazy as _

from mtp.apps.assessments.forms import AssessableMixin
from mtp.apps.common.forms_utils import OrderableInlineFormset
from mtp.apps.common.utils import mod_lazy

from .constants import ANSWER_TITLE_MAX_LENGTH, QUESTION_TITLE_MAX_LENGTH
from .models import (
    Workshop,
    WorkshopStep,
    WorkshopStepImage,
    WorkshopStepQuestion,
    WorkshopStepQuestionAnswer,
)


class WorkshopForm(forms.ModelForm):
    """Form for ``Workshop`` model.

    Notes
    -----
    This form should be used when assessment isn't active.

    """

    class Meta:
        model = Workshop
        fields = (
            'name',
            'description',
            'is_broadcastable',
            'enable_score',
        )


class WorkshopAssessableForm(AssessableMixin, WorkshopForm):
    """Form for ``Workshop`` assessable model.

    Notes
    -----
    This form should be used when assessment is active.

    """

    class Meta(WorkshopForm.Meta):
        fields = WorkshopForm.Meta.fields + (
            'is_assessing',
            'is_steps_order_random',
            'are_questions_mandatory',
            'is_questions_answers_order_random',
        )


class WorkshopStepBaseForm(forms.ModelForm):
    """Form for models which inherit of ``WorkshopStep``.

    Attributes
    ----------
    workshop: Workshop
        Optional.
        The workshop of the ``WorkshopStep`` instance to create/update.

    """

    workshop = None

    def __init__(self, *args, **kwargs):
        """Initialize the form with the provided workshop.

        For the parameters, see ``django.forms.ModelForm``"""

        self.workshop = kwargs.pop('workshop', None)
        super().__init__(*args, **kwargs)

    def save(self, commit=True):
        """Set the instance workshop if provided.

        For the parameters, see ``django.forms.ModelForm``
        """

        if self.workshop:
            self.instance.workshop = self.workshop

        return super().save(commit=commit)


class WorkshopStepsDeleteForm(forms.Form):
    """Form to select and soft delete a list of ``WorkshopStep`` instance

    We expect ``workshop`` to be part of the ``kwargs``.

    For the parameters, see ``django.forms.ModelForm``

    """

    steps = forms.ModelMultipleChoiceField(
        queryset=WorkshopStep.objects.non_deleted()
    )

    def __init__(self, *args, **kwargs):
        """Initialize the form with the provided workshop and update the steps queryset accordingly

        For the parameters, see ``django.forms.ModelForm``"""

        workshop = kwargs.pop('workshop', None)

        super().__init__(*args, **kwargs)

        self.fields['steps'].queryset = workshop.steps.non_deleted()


class WorkshopStepQuestionForm(WorkshopStepBaseForm):
    """Form for ``WorkshopStepQuestion`` model.

    Notes
    -----
    This form should be used when assessment isn't active.

    """

    class Meta:
        model = WorkshopStepQuestion
        fields = (
            'title',
            'is_multiple_choices',
            'is_all_or_nothing',
        )

    def __init__(self, *args, **kwargs):
        """Prepare the ``title`` field.

        For the parameters, see ``django.forms.ModelForm``"""
        super().__init__(*args, **kwargs)

        # Hack: apply a maximal length limit to fit the iOS display.
        self.fields['title'].widget.attrs['maxlength'] = QUESTION_TITLE_MAX_LENGTH
        self.fields['title'].help_text = mod_lazy(_(
            "Field length limited to %d characters."
        ), QUESTION_TITLE_MAX_LENGTH)

    def clean(self):
        """Check that the `is_multiple_choices` is enable to activate `is_all_or_nothing` option."""

        cleaned_data = super().clean()

        if cleaned_data['is_all_or_nothing'] and not cleaned_data['is_multiple_choices']:
            self.add_error('is_all_or_nothing', _("You must activate 'is_multiple_choices' option "
                                                  "to enable it."))

        return cleaned_data


class WorkshopStepQuestionAssessableForm(AssessableMixin, WorkshopStepQuestionForm):
    """Form for ``WorkshopStepQuestion`` assessable model.

    Notes
    -----
    This form should be used when assessment is active.

    """

    class Meta(WorkshopStepQuestionForm.Meta):
        fields = WorkshopStepQuestionForm.Meta.fields + (
            'dimensions',
        )


class WorkshopStepImageForm(WorkshopStepBaseForm):
    """Form for ``WorkshopStepImage`` model."""

    class Meta:
        model = WorkshopStepImage
        fields = (
            'title',
            'image',
        )


class WorkshopStepQuestionAnswerForm(forms.ModelForm):

    class Meta:
        model = WorkshopStepQuestionAnswer
        fields = (
            'label', 'is_correct', 'points',
        )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Limitation of characters for displaying correctly label in iOS without modify database
        self.fields['label'].widget.attrs['maxlength'] = ANSWER_TITLE_MAX_LENGTH
        self.fields['label'].help_text = _("Field limited to %d characters.") % (
            ANSWER_TITLE_MAX_LENGTH
        )


WorkshopStepQuestionAnswerFormSet = inlineformset_factory(  # pylint: disable=invalid-name
    WorkshopStepQuestion,
    WorkshopStepQuestionAnswer,
    form=WorkshopStepQuestionAnswerForm,
    formset=OrderableInlineFormset,
    extra=0,  # Be sure to have all forms displayed even if no answers exist.
    min_num=0,   # Allow no choices for open questions.
    max_num=5,  # And we don't want more than the defined max.
    validate_max=True,  # Let django manage the max number of answers.
    can_delete=True,  # Default value but explicit is better than implicit,
    can_order=True,  # Default to False but here we want ordering
)
