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

from django import forms
from django.core.exceptions import ValidationError

from .models import (
    PdfMedia,
    Presentation,
    PresentationMedia,
    Video,
    VideoMedia,
)


class PresentationForm(forms.ModelForm):
    """Form for ``Presentation`` model.

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

    """

    pdf = forms.FileField(
        help_text=PdfMedia._meta.get_field('file').help_text,
    )
    restricted_pdf = forms.FileField(
        required=False,
        help_text=PdfMedia._meta.get_field('file').help_text,
    )

    class Meta:
        model = Presentation
        fields = (
            'name',
            'description',
            'is_accessible_by_trainees',
            'pdf',
            'restricted_pdf',
        )

    def __init__(self, *args, **kwargs):
        """Populate the ``main_content_file`` and ``restricted_content_file`` fields"""

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

        # If we are editing an existing instance
        if self.instance and self.instance.pk:
            self.fields['pdf'].initial = self.instance.pdf.file

            if self.instance.restricted_pdf:
                self.fields['restricted_pdf'].initial = self.instance.restricted_pdf.file

    def clean_pdf(self):
        """Check that the ``pdf`` file is valid

        We are doing so by creating a new ``PdfMedia`` and calling ``clean_fields``.

        """

        file = self.cleaned_data.get('pdf')
        pdf_media = PdfMedia(file=file)

        try:
            pdf_media.clean_fields(exclude=['original_version', 'parent_version'])
        except ValidationError as error:
            # Append each error message raised by the ``pdf_media`` to the ``pdf`` field.
            for message in error.messages:
                self.add_error('pdf', message)

        return file

    def clean_restricted_pdf(self):
        """Check that the ``restricted_pdf`` file is valid

        We are doing so by creating a new ``PdfMedia`` and calling ``clean_fields``.

        """

        file = self.cleaned_data.get('restricted_pdf')

        # This field might be set to ``False`` in the case of the file was deleted
        if not file:
            return file

        pdf_media = PdfMedia(file=file)

        try:
            pdf_media.clean_fields(exclude=['original_version', 'parent_version'])
        except ValidationError as error:
            # Append each error message raised by the ``pdf_media`` to the ``restricted_pdf`` field.
            for message in error.messages:
                self.add_error('restricted_pdf', message)

        return file

    def save(self, commit=True):
        """Create the ``PdfMedia``s and associate them with the ``Presentation``

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

        Returns
        -------
        ``Presentation``

        """

        presentation = super().save(commit=False)

        # We need to save the ``PresentationMedia`` associated with this presentation
        def save_m2m():
            """Handle the linked ``PresentationMedia``s"""

            # First, clean all the media associated with this presentation
            PresentationMedia.objects.filter(presentation=presentation).delete()

            # Now, re-create the media(s)

            # Firstly, the main pdf
            pdf_file = self.cleaned_data.get('pdf')
            pdf_media = PdfMedia.objects.create(file=pdf_file)
            PresentationMedia.objects.create(
                presentation=presentation,
                media=pdf_media
            )

            # And the restricted one, if applicable
            restricted_pdf_file = self.cleaned_data.get('restricted_pdf')
            if restricted_pdf_file:
                restricted_pdf_media = PdfMedia.objects.create(file=restricted_pdf_file)
                PresentationMedia.objects.create(
                    presentation=presentation,
                    media=restricted_pdf_media,
                    is_restricted=True
                )

        self.save_m2m = save_m2m  # pylint: disable=attribute-defined-outside-init

        if commit:
            presentation.save()
            self.save_m2m()

        return presentation


class VideoForm(forms.ModelForm):
    """Form for ``Video`` model.

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

    """

    video = forms.FileField(
        help_text=VideoMedia._meta.get_field('file').help_text,
    )

    class Meta:
        model = Video
        fields = (
            'name',
            'description',
            'video',
        )

    def __init__(self, *args, **kwargs):
        """Populate the ``video`` field if we are editing an existing instance"""

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

        if self.instance and self.instance.pk:
            self.fields['video'].initial = self.instance.media.file

    def clean_video(self):
        """Check that the video file is valid

        We are doing so by creating a new ``VideoMediaContent`` and calling ``clean_fields``.

        """

        video_file = self.cleaned_data.get('video')

        video_media = VideoMedia(file=video_file)

        try:
            video_media.clean_fields(exclude=['original_version', 'parent_version'])
        except ValidationError as error:
            # Append each error message raised by the ``video_content`` to the ``video`` field.
            for message in error.messages:
                self.add_error('video', message)

        return video_file

    def save(self, commit=True):
        """Create the ``VideoMediaContent`` and associate it with the ``Video``

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

        Returns
        -------
        ``Video``

        """

        video_instance = super().save(commit=False)

        if self.instance and self.instance.id:
            video_instance.media.file = self.cleaned_data.get('video')
        else:
            video_media = VideoMedia(file=self.cleaned_data.get('video'))
            video_instance.media = video_media

        return video_instance
