"""This module contains the forms for the ``questionnaires`` app"""

from django import forms
from django.contrib.contenttypes.forms import generic_inlineformset_factory

from mtp.apps.common.forms_utils import GenericOrderableInlineFormSet

from .models import (
    Choice,
    ChoicesQuestion,
    ImageChoicesQuestion,
    LivePolling,
    LiveQuiz,
    OpenQuestion,
    Question
)


class QuestionsDeleteForm(forms.Form):
    """Form to select and soft delete a list of ``Question`` instances

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

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

    """

    questions = forms.ModelMultipleChoiceField(
        queryset=Question.objects.non_deleted()
    )

    def __init__(self, *args, **kwargs):
        """Initialize the form with the provided questionnaire and update the question queryset

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

        """

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

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

        self.fields['questions'].queryset = questionnaire.questions.non_deleted()


class QuestionBaseForm(forms.ModelForm):
    """Form for the ``Question`` subclasses

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

    Attributes
    ----------
    questionnaire: Questionnaire
        Optional.
        The questionnaire of the ``Question`` instance to create/update.

    """

    questionnaire = None

    class Meta:
        fields = (
            'label',
        )

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

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

        """

        self.questionnaire = kwargs.pop('questionnaire', None)

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

        # Set the max length of the label field, accordingly to the ``Questionnaire`` subclass
        if isinstance(self.questionnaire, (LiveQuiz, LivePolling)):
            self.fields['label'].widget.attrs['maxlength'] = 140

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

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

        """

        if self.questionnaire:
            self.instance.questionnaire = self.questionnaire

        return super().save(commit=commit)


class ChoicesQuestionForm(QuestionBaseForm):
    """Form for the ``ChoicesQuestion`` model.

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

    """

    def __init__(self, *args, **kwargs):
        """Override the "maxlength" attribute of the label field widget

        The ``ImageChoicesQuestion`` cannot have a label field longer than 140 chars.

        """

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

        # Set the max length of the label field, accordingly to the ``Questionnaire`` subclass
        if issubclass(self.Meta.model, ImageChoicesQuestion):
            self.fields['label'].widget.attrs['maxlength'] = 140

    class Meta:
        model = ChoicesQuestion
        fields = QuestionBaseForm.Meta.fields + (
            'label',
            'is_multiple_choices',
        )


class ScoringChoicesQuestionForm(ChoicesQuestionForm):
    """Form for the ``ChoicesQuestion`` model

    This form add the "points" field, and should be used when this question
    is linked with a "scoring" ``Questionnaire``.

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

    """

    class Meta:
        model = ChoicesQuestion
        fields = ChoicesQuestionForm.Meta.fields + (
            'points',
        )

    def __init__(self, *args, **kwargs):
        """Disable the "is_multiple_choices" field"""

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

        self.fields['is_multiple_choices'].widget.attrs['onclick'] = 'return false;'


class ImageChoicesQuestionForm(ChoicesQuestionForm):
    """Form for the ``ImageChoicesQuestion`` model."""

    class Meta:
        model = ImageChoicesQuestion
        fields = ChoicesQuestionForm.Meta.fields + (
            'image',
        )


class ScoringImageChoicesQuestionForm(ScoringChoicesQuestionForm):
    """Form for the ``ImageChoicesQuestion`` model.

    This form add the "points" field, and should be used when this question
    is linked with a "scoring" ``Questionnaire``.

    """

    class Meta:
        model = ImageChoicesQuestion
        fields = ScoringChoicesQuestionForm.Meta.fields + (
            'image',
        )


class OpenQuestionForm(QuestionBaseForm):
    """Form for the ``OpenQuestion`` model."""

    class Meta:
        model = OpenQuestion
        fields = QuestionBaseForm.Meta.fields


class ChoiceForm(forms.ModelForm):
    """Form for the ``Choice`` model.

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

    """

    def __init__(self, *args, **kwargs):
        """Disable the "is_multiple_choices" field"""

        self.questionnaire = kwargs.pop('questionnaire')

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

        # Set the max length of the label field, accordingly to the ``Questionnaire`` "live" status
        if self.questionnaire.is_live:
            self.fields['label'].widget.attrs['maxlength'] = 140

    class Meta:
        model = Choice
        fields = (
            'label',
        )


class ScoringChoiceForm(ChoiceForm):
    """Form for the ``Choice`` model

    This form add the "is_valid" field, and should be used when the question linked to this
    choice is linked with a scoring ``Questionnaire``.

    """

    class Meta:
        model = Choice
        fields = ChoiceForm.Meta.fields + (
            'is_valid',
        )


ChoicesQuestionChoicesFormSet = generic_inlineformset_factory(  # pylint: disable=invalid-name
    Choice,
    form=ChoiceForm,
    formset=GenericOrderableInlineFormSet,
    ct_field='question_content_type',
    fk_field='question_id',
    extra=0,  # Be sure to have all forms displayed even if no choices exist.
    min_num=1,   # At least one choice is required
    max_num=10,  # And we don't want more than the defined max.
    validate_max=True,  # Let django manage the max number of choices.
    can_delete=True,  # Default value but explicit is better than implicit,
    can_order=True,  # Default to False but here we want ordering
)

ScoringChoicesQuestionChoicesFormSet = generic_inlineformset_factory(  # pylint: disable=invalid-name
    Choice,
    form=ScoringChoiceForm,
    formset=GenericOrderableInlineFormSet,
    ct_field='question_content_type',
    fk_field='question_id',
    extra=0,  # Be sure to have all forms displayed even if no choices exist.
    min_num=1,   # At least one choice is required
    max_num=10,  # And we don't want more than the defined max.
    validate_max=True,  # Let django manage the max number of choices.
    can_delete=True,  # Default value but explicit is better than implicit,
    can_order=True,  # Default to False but here we want ordering
)
