"""This module holds views tests for the ``photostories``."""
from io import BytesIO
from zipfile import ZipFile

from django.core.urlresolvers import reverse

from slugify import slugify

from mtp.apps.photostories.factories import PhotoFactory, PhotostoryFactory, StripFactory
from mtp.apps.photostories.models import Photostory, Photo
from mtp.apps.photostories.tests.test_cases import PhotostoryTestCase
from mtp.apps.trainings.factories import TrainingSessionFactory


class PhotostoryViewsTestCase(PhotostoryTestCase):
    """Test case that tests the ``Photostory`` related views."""

    @classmethod
    def setUpTestData(cls):
        super().setUpTestData()

        cls.urls_to_test = [
            Photostory.get_create_url(cls.training),
            cls.photostory.get_detail_url(),
            cls.photostory.get_edit_url(),
            cls.photostory.get_delete_url(),
        ]

        cls.training.version_state = cls.training.VERSION_STATES.DRAFT
        cls.training.save()

    def test_non_training_owner_should_not_have_access(self):
        """Test that users who don't own the training should not be allowed to access the views"""

        self.login_as_admin()

        for url in self.urls_to_test:
            with self.subTest(url=url):
                response = self.client.get(url)
                self.assertEqual(response.status_code, 404)

    def test_training_owner_should_have_access(self):
        """Test that user of document should be allowed to access the document."""

        self.login_as_trainer()

        for url in self.urls_to_test:
            with self.subTest(url=url):
                response = self.client.get(url)
                self.assertEqual(response.status_code, 200)


class PhotostoryListViewBySessionTestCase(PhotostoryTestCase):
    """Test for the ``PhotostoryListViewBySession``."""

    def test_photostory_count_by_session(self):
        """Test the context data return to the template"""

        # We connect as trainer
        self.login_as_trainer()

        url = reverse(
            'photostories:photostory-list-by-session',
            kwargs={
                'session_uuid': self.training_session.pk,
            }
        )

        response = self.client.get(url)

        # The view work
        self.assertEqual(
            response.status_code,
            200
        )

        # Should contains data for all photostories in the session
        self.assertEqual(
            len(response.context['strips_count']),
            len(self.photostories)
        )
        self.assertEqual(
            len(response.context['strips_count']),
            len(response.context['photos_count'])
        )

        # We got the correct context data
        self.assertEqual(
            response.context['strips_count'][self.photostory],
            2
        )
        self.assertEqual(
            response.context['photos_count'][self.photostory],
            6
        )

        # We create a new strip in this session
        StripFactory(photostory=self.photostory, session=self.training_session)

        # We should have one more strip in this session
        response = self.client.get(url)
        self.assertEqual(
            response.context['strips_count'][self.photostory],
            3
        )
        self.assertEqual(
            response.context['photos_count'][self.photostory],
            6
        )
        # then a new photo
        PhotoFactory(strip=self.strip)

        # We should have one more photo in this session
        response = self.client.get(url)
        self.assertEqual(
            response.context['strips_count'][self.photostory],
            3
        )
        self.assertEqual(
            response.context['photos_count'][self.photostory],
            7
        )

        # We create a new live photostory and a new strip in the  session
        new_photostory = PhotostoryFactory(
            training=None,
            session=self.training_session
        )
        StripFactory(photostory=new_photostory, session=self.training_session)

        # Sould contains data for all photostories for the session
        response = self.client.get(url)
        self.assertEqual(
            len(response.context['strips_count']),
            len(self.photostories) + 1
        )
        self.assertEqual(
            len(response.context['strips_count']),
            len(response.context['photos_count'])
        )
        # We should have one strip in the new photostory
        self.assertEqual(
            response.context['strips_count'][new_photostory],
            1
        )

        # We create a new session with its request
        new_session = TrainingSessionFactory(training=self.training, trainer=self.admin)
        new_url = reverse(
            'photostories:photostory-list-by-session',
            kwargs={
                'session_uuid': new_session.pk,
            }
        )

        # The list should contain 0 strip and 0 photo for the session in the photostory
        response = self.client.get(new_url)
        self.assertEqual(
            response.context['strips_count'][self.photostory],
            0
        )
        self.assertEqual(
            response.context['photos_count'][self.photostory],
            0
        )

        # We create a new strip and a new photo in this new session
        new_strip = StripFactory(photostory=self.photostory, session=new_session)
        PhotoFactory(strip=new_strip)

        # The list should contain 1 strip and 1 photo for the new session
        response = self.client.get(new_url)
        self.assertEqual(
            response.context['strips_count'][self.photostory],
            1
        )
        self.assertEqual(
            response.context['photos_count'][self.photostory],
            1
        )


class PhotostoryExportViewTestCase(PhotostoryTestCase):
    """Test for the ``PhotostoryExportView``."""

    def test_zip_contains_photo_filtered_by_session(self):
        """Test the download url."""

        url = reverse(
            'photostories:photostory-export-by-session',
            kwargs={
                'photostory_uuid': self.photostory.pk,
                'session_uuid': self.training_session.pk
            }
        )

        # We connect as trainer
        self.login_as_trainer()

        # Get the zip file
        response = self.client.get(url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.get('Content-Disposition'), "attachment; filename=%s.%s" % (
            slugify(self.photostory.name),
            'zip'
        ))

        # Test the content of the zip file
        with BytesIO(response.content) as content_file:
            with ZipFile(content_file, 'r') as zipped_file:
                # It should be valid
                self.assertIsNone(zipped_file.testzip())
                self.assertIn('%s/1.jpg' % self.strip.name, zipped_file.namelist())

                # Count the number of photo that the archive should contain
                nb_photo = Photo.objects.filter(strip__photostory=self.photostory).filter(
                    strip__session=self.training_session
                ).count()
                # The archive should contain as many file as photos
                self.assertEqual(len(zipped_file.namelist()), nb_photo)

        # We create a new strip in an other session
        strip = StripFactory(photostory=self.photostory)
        # then a new photo in this new strip
        PhotoFactory(strip=strip)

        # Get the zip file
        response = self.client.get(url)

        # Test the content of the zip file
        with BytesIO(response.content) as content_file:
            with ZipFile(content_file, 'r') as zipped_file:
                # We should have still the same number of photo
                self.assertEqual(len(zipped_file.namelist()), nb_photo)
