# -*- coding: utf-8 -*-
"""
Tests for video outline API
"""
import ddt
import itertools
import json

from collections import namedtuple
from mock import Mock
from uuid import uuid4

from django.conf import settings
from edxval import api
from milestones.tests.utils import MilestonesTestCaseMixin
from mock import patch
from nose.plugins.attrib import attr

from mobile_api.models import MobileApiConfig
from mobile_api.testutils import MobileAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin
from openedx.core.djangoapps.course_groups.cohorts import add_user_to_cohort, remove_user_from_cohort
from openedx.core.djangoapps.course_groups.models import CourseUserGroupPartitionGroup
from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.tests.factories import ItemFactory
from xmodule.partitions.partitions import Group, UserPartition
from xmodule.video_module import transcripts_utils


class TestVideoAPITestCase(MobileAPITestCase):
    """
    Base test class for video related mobile APIs
    """
    def setUp(self):
        super(TestVideoAPITestCase, self).setUp()
        self.section = ItemFactory.create(
            parent=self.course,
            category="chapter",
            display_name=u"test factory section omega \u03a9",
        )
        self.sub_section = ItemFactory.create(
            parent=self.section,
            category="sequential",
            display_name=u"test subsection omega \u03a9",
        )

        self.unit = ItemFactory.create(
            parent=self.sub_section,
            category="vertical",
            metadata={'graded': True, 'format': 'Homework'},
            display_name=u"test unit omega \u03a9",
        )
        self.other_unit = ItemFactory.create(
            parent=self.sub_section,
            category="vertical",
            metadata={'graded': True, 'format': 'Homework'},
            display_name=u"test unit omega 2 \u03a9",
        )
        self.nameless_unit = ItemFactory.create(
            parent=self.sub_section,
            category="vertical",
            metadata={'graded': True, 'format': 'Homework'},
            display_name=None,
        )

        self.edx_video_id = 'testing-123'
        self.video_url = 'http://val.edx.org/val/video.mp4'
        self.video_url_high = 'http://val.edx.org/val/video_high.mp4'
        self.video_url_low = 'http://val.edx.org/val/video_low.mp4'
        self.youtube_url = 'http://val.edx.org/val/youtube.mp4'
        self.html5_video_url = 'http://video.edx.org/html5/video.mp4'

        api.create_profile('youtube')
        api.create_profile('mobile_high')
        api.create_profile('mobile_low')

        # create the video in VAL
        api.create_video({
            'edx_video_id': self.edx_video_id,
            'status': 'test',
            'client_video_id': u"test video omega \u03a9",
            'duration': 12,
            'courses': [unicode(self.course.id)],
            'encoded_videos': [
                {
                    'profile': 'youtube',
                    'url': 'xyz123',
                    'file_size': 0,
                    'bitrate': 1500
                },
                {
                    'profile': 'mobile_low',
                    'url': self.video_url,
                    'file_size': 12345,
                    'bitrate': 250
                },
                {
                    'profile': 'mobile_high',
                    'url': self.video_url_high,
                    'file_size': 99999,
                    'bitrate': 250
                },

            ]})

        # Set requested profiles
        MobileApiConfig(video_profiles="mobile_low,mobile_high,youtube").save()


class TestVideoAPIMixin(object):
    """
    Mixin class that provides helpers for testing video related mobile APIs
    """
    def _create_video_with_subs(self, custom_subid=None):
        """
        Creates and returns a video with stored subtitles.
        """
        subid = custom_subid or uuid4().hex
        transcripts_utils.save_subs_to_store(
            {
                'start': [100, 200, 240, 390, 1000],
                'end': [200, 240, 380, 1000, 1500],
                'text': [
                    'subs #1',
                    'subs #2',
                    'subs #3',
                    'subs #4',
                    'subs #5'
                ]
            },
            subid,
            self.course)
        return ItemFactory.create(
            parent=self.unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test video omega \u03a9",
            sub=subid
        )

    def _verify_paths(self, course_outline, path_list, outline_index=0):
        """
        Takes a path_list and compares it against the course_outline

        Attributes:
            course_outline (list): A list of dictionaries that includes a 'path'
                and 'named_path' field which we will be comparing path_list to
            path_list (list): A list of the expected strings
            outline_index (int): Index into the course_outline list for which the
                path is being tested.
        """
        path = course_outline[outline_index]['path']
        self.assertEqual(len(path), len(path_list))
        for i in range(len(path_list)):
            self.assertEqual(path_list[i], path[i]['name'])
        #named_path will be deprecated eventually
        named_path = course_outline[outline_index]['named_path']
        self.assertEqual(len(named_path), len(path_list))
        for i in range(len(path_list)):
            self.assertEqual(path_list[i], named_path[i])

    def _setup_course_partitions(self, scheme_id='random', is_cohorted=False):
        """Helper method to configure the user partitions in the course."""
        self.partition_id = 0  # pylint: disable=attribute-defined-outside-init
        self.course.user_partitions = [
            UserPartition(
                self.partition_id, 'first_partition', 'First Partition',
                [Group(0, 'alpha'), Group(1, 'beta')],
                scheme=None, scheme_id=scheme_id
            ),
        ]
        self.course.cohort_config = {'cohorted': is_cohorted}
        self.store.update_item(self.course, self.user.id)

    def _setup_group_access(self, xblock, partition_id, group_ids):
        """Helper method to configure the partition and group mapping for the given xblock."""
        xblock.group_access = {partition_id: group_ids}
        self.store.update_item(xblock, self.user.id)

    def _setup_split_module(self, sub_block_category):
        """Helper method to configure a split_test unit with children of type sub_block_category."""
        self._setup_course_partitions()
        self.split_test = ItemFactory.create(  # pylint: disable=attribute-defined-outside-init
            parent=self.unit,
            category="split_test",
            display_name=u"split test unit",
            user_partition_id=0,
        )
        sub_block_a = ItemFactory.create(
            parent=self.split_test,
            category=sub_block_category,
            display_name=u"split test block a",
        )
        sub_block_b = ItemFactory.create(
            parent=self.split_test,
            category=sub_block_category,
            display_name=u"split test block b",
        )
        self.split_test.group_id_to_child = {
            str(index): url for index, url in enumerate([sub_block_a.location, sub_block_b.location])
        }
        self.store.update_item(self.split_test, self.user.id)
        return sub_block_a, sub_block_b


@attr(shard=2)
class TestNonStandardCourseStructure(MobileAPITestCase, TestVideoAPIMixin, MilestonesTestCaseMixin):
    """
    Tests /api/mobile/v0.5/video_outlines/courses/{course_id} with no course set
    """
    REVERSE_INFO = {'name': 'video-summary-list', 'params': ['course_id']}

    def setUp(self):
        super(TestNonStandardCourseStructure, self).setUp()
        self.chapter_under_course = ItemFactory.create(
            parent=self.course,
            category="chapter",
            display_name=u"test factory chapter under course omega \u03a9",
        )
        self.section_under_course = ItemFactory.create(
            parent=self.course,
            category="sequential",
            display_name=u"test factory section under course omega \u03a9",
        )
        self.section_under_chapter = ItemFactory.create(
            parent=self.chapter_under_course,
            category="sequential",
            display_name=u"test factory section under chapter omega \u03a9",
        )
        self.vertical_under_course = ItemFactory.create(
            parent=self.course,
            category="vertical",
            display_name=u"test factory vertical under course omega \u03a9",
        )
        self.vertical_under_section = ItemFactory.create(
            parent=self.section_under_chapter,
            category="vertical",
            display_name=u"test factory vertical under section omega \u03a9",
        )

    def test_structure_course_video(self):
        """
        Tests when there is a video without a vertical directly under course
        """
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.course,
            category="video",
            display_name=u"test factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(section_url, r'courseware$')
        self.assertEqual(section_url, unit_url)

        self._verify_paths(course_outline, [])

    def test_structure_course_vert_video(self):
        """
        Tests when there is a video under vertical directly under course
        """
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.vertical_under_course,
            category="video",
            display_name=u"test factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(
            section_url,
            r'courseware/test_factory_vertical_under_course_omega_%CE%A9/$'
        )
        self.assertEqual(section_url, unit_url)

        self._verify_paths(
            course_outline,
            [
                u'test factory vertical under course omega \u03a9'
            ]
        )

    def test_structure_course_chap_video(self):
        """
        Tests when there is a video directly under chapter
        """
        self.login_and_enroll()

        ItemFactory.create(
            parent=self.chapter_under_course,
            category="video",
            display_name=u"test factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(
            section_url,
            r'courseware/test_factory_chapter_under_course_omega_%CE%A9/$'
        )

        self.assertEqual(section_url, unit_url)

        self._verify_paths(
            course_outline,
            [
                u'test factory chapter under course omega \u03a9',
            ]
        )

    def test_structure_course_section_video(self):
        """
        Tests when chapter is none, and video under section under course
        """
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.section_under_course,
            category="video",
            display_name=u"test factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(
            section_url,
            r'courseware/test_factory_section_under_course_omega_%CE%A9/$'
        )

        self.assertEqual(section_url, unit_url)

        self._verify_paths(
            course_outline,
            [
                u'test factory section under course omega \u03a9',
            ]
        )

    def test_structure_course_chap_section_video(self):
        """
        Tests when chapter and sequential exists, with a video with no vertical.
        """
        self.login_and_enroll()

        ItemFactory.create(
            parent=self.section_under_chapter,
            category="video",
            display_name=u"meow factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(
            section_url,
            (
                r'courseware/test_factory_chapter_under_course_omega_%CE%A9/' +
                'test_factory_section_under_chapter_omega_%CE%A9/$'
            )
        )

        self.assertEqual(section_url, unit_url)

        self._verify_paths(
            course_outline,
            [
                u'test factory chapter under course omega \u03a9',
                u'test factory section under chapter omega \u03a9',
            ]
        )

    def test_structure_course_section_vert_video(self):
        """
        Tests chapter->section->vertical->unit
        """
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.vertical_under_section,
            category="video",
            display_name=u"test factory video omega \u03a9",
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertRegexpMatches(
            section_url,
            (
                r'courseware/test_factory_chapter_under_course_omega_%CE%A9/' +
                'test_factory_section_under_chapter_omega_%CE%A9/$'
            )
        )
        self.assertRegexpMatches(
            unit_url,
            (
                r'courseware/test_factory_chapter_under_course_omega_%CE%A9/' +
                'test_factory_section_under_chapter_omega_%CE%A9/1$'
            )
        )

        self._verify_paths(
            course_outline,
            [
                u'test factory chapter under course omega \u03a9',
                u'test factory section under chapter omega \u03a9',
                u'test factory vertical under section omega \u03a9'
            ]
        )


@attr(shard=2)
@ddt.ddt
class TestVideoSummaryList(TestVideoAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin,
                           TestVideoAPIMixin, MilestonesTestCaseMixin):
    """
    Tests for /api/mobile/v0.5/video_outlines/courses/{course_id}..
    """
    REVERSE_INFO = {'name': 'video-summary-list', 'params': ['course_id']}

    def test_only_on_web(self):
        self.login_and_enroll()

        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 0)

        subid = uuid4().hex
        transcripts_utils.save_subs_to_store(
            {
                'start': [100],
                'end': [200],
                'text': [
                    'subs #1',
                ]
            },
            subid,
            self.course)

        ItemFactory.create(
            parent=self.unit,
            category="video",
            display_name=u"test video",
            only_on_web=True,
            subid=subid
        )

        course_outline = self.api_response().data

        self.assertEqual(len(course_outline), 1)

        self.assertIsNone(course_outline[0]["summary"]["video_url"])
        self.assertIsNone(course_outline[0]["summary"]["video_thumbnail_url"])
        self.assertEqual(course_outline[0]["summary"]["duration"], 0)
        self.assertEqual(course_outline[0]["summary"]["size"], 0)
        self.assertEqual(course_outline[0]["summary"]["name"], "test video")
        self.assertEqual(course_outline[0]["summary"]["transcripts"], {})
        self.assertIsNone(course_outline[0]["summary"]["language"])
        self.assertEqual(course_outline[0]["summary"]["category"], "video")
        self.assertTrue(course_outline[0]["summary"]["only_on_web"])

    def test_mobile_api_video_profiles(self):
        """
        Tests VideoSummaryList with different MobileApiConfig video_profiles
        """
        self.login_and_enroll()
        edx_video_id = "testing_mobile_high"
        api.create_video({
            'edx_video_id': edx_video_id,
            'status': 'test',
            'client_video_id': u"test video omega \u03a9",
            'duration': 12,
            'courses': [unicode(self.course.id)],
            'encoded_videos': [
                {
                    'profile': 'youtube',
                    'url': self.youtube_url,
                    'file_size': 2222,
                    'bitrate': 4444
                },
                {
                    'profile': 'mobile_high',
                    'url': self.video_url_high,
                    'file_size': 111,
                    'bitrate': 333
                },

            ]})
        ItemFactory.create(
            parent=self.other_unit,
            category="video",
            display_name=u"testing mobile high video",
            edx_video_id=edx_video_id,
        )

        expected_output = {
            'all_sources': [],
            'category': u'video',
            'video_thumbnail_url': None,
            'language': u'en',
            'name': u'testing mobile high video',
            'video_url': self.video_url_high,
            'duration': 12.0,
            'transcripts': {
                'en': 'http://testserver/api/mobile/v0.5/video_outlines/transcripts/{}/testing_mobile_high_video/en'.format(self.course.id)  # pylint: disable=line-too-long
            },
            'only_on_web': False,
            'encoded_videos': {
                u'mobile_high': {
                    'url': self.video_url_high,
                    'file_size': 111
                },
                u'youtube': {
                    'url': self.youtube_url,
                    'file_size': 2222
                }
            },
            'size': 111
        }

        # The transcript was not entered, so it should not be found!
        # This is the default behaviour at courses.edX.org, based on `FALLBACK_TO_ENGLISH_TRANSCRIPTS`
        transcripts_response = self.client.get(expected_output['transcripts']['en'])
        self.assertEqual(404, transcripts_response.status_code)

        with patch.dict(settings.FEATURES, FALLBACK_TO_ENGLISH_TRANSCRIPTS=False):
            # Other platform installations may override this setting
            # This ensures that the server don't return empty English transcripts when there's none!
            self.assertFalse(self.api_response().data[0]['summary'].get('transcripts'))

        # Testing when video_profiles='mobile_low,mobile_high,youtube'
        course_outline = self.api_response().data
        course_outline[0]['summary'].pop("id")
        self.assertEqual(course_outline[0]['summary'], expected_output)

        # Testing when there is no mobile_low, and that mobile_high doesn't show
        MobileApiConfig(video_profiles="mobile_low,youtube").save()

        course_outline = self.api_response().data

        expected_output['encoded_videos'].pop('mobile_high')
        expected_output['video_url'] = self.youtube_url
        expected_output['size'] = 2222

        course_outline[0]['summary'].pop("id")
        self.assertEqual(course_outline[0]['summary'], expected_output)

        # Testing where youtube is the default video over mobile_high
        MobileApiConfig(video_profiles="youtube,mobile_high").save()

        course_outline = self.api_response().data

        expected_output['encoded_videos']['mobile_high'] = {
            'url': self.video_url_high,
            'file_size': 111
        }

        course_outline[0]['summary'].pop("id")
        self.assertEqual(course_outline[0]['summary'], expected_output)

    def test_mobile_api_html5_sources(self):
        """
        Tests VideoSummaryList without the video pipeline, using fallback HTML5 video URLs
        """
        self.login_and_enroll()
        descriptor = ItemFactory.create(
            parent=self.other_unit,
            category="video",
            display_name=u"testing html5 sources",
            edx_video_id=None,
            source=self.video_url_high,
            html5_sources=[self.video_url_low],
        )
        expected_output = {
            'all_sources': [self.video_url_low, self.video_url_high],
            'category': u'video',
            'video_thumbnail_url': None,
            'language': u'en',
            'id': unicode(descriptor.scope_ids.usage_id),
            'name': u'testing html5 sources',
            'video_url': self.video_url_low,
            'duration': None,
            'transcripts': {
                'en': 'http://testserver/api/mobile/v0.5/video_outlines/transcripts/{}/testing_html5_sources/en'.format(self.course.id)  # pylint: disable=line-too-long
            },
            'only_on_web': False,
            'encoded_videos': None,
            'size': 0,
        }

        course_outline = self.api_response().data
        self.assertEqual(course_outline[0]['summary'], expected_output)

    def test_video_not_in_val(self):
        self.login_and_enroll()
        self._create_video_with_subs()
        ItemFactory.create(
            parent=self.other_unit,
            category="video",
            edx_video_id="some_non_existent_id_in_val",
            display_name=u"some non existent video in val",
            html5_sources=[self.html5_video_url]
        )

        summary = self.api_response().data[1]['summary']
        self.assertEqual(summary['name'], "some non existent video in val")
        self.assertIsNone(summary['encoded_videos'])
        self.assertIsNone(summary['duration'])
        self.assertEqual(summary['size'], 0)
        self.assertEqual(summary['video_url'], self.html5_video_url)

    def test_course_list(self):
        self.login_and_enroll()
        self._create_video_with_subs()
        ItemFactory.create(
            parent=self.other_unit,
            category="video",
            display_name=u"test video omega 2 \u03a9",
            html5_sources=[self.html5_video_url]
        )
        ItemFactory.create(
            parent=self.other_unit,
            category="video",
            display_name=u"test video omega 3 \u03a9",
            source=self.html5_video_url
        )
        ItemFactory.create(
            parent=self.unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test draft video omega \u03a9",
            visible_to_staff_only=True,
        )

        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 3)
        vid = course_outline[0]
        self.assertIn('test_subsection_omega_%CE%A9', vid['section_url'])
        self.assertIn('test_subsection_omega_%CE%A9/1', vid['unit_url'])
        self.assertIn(u'test_video_omega_\u03a9', vid['summary']['id'])
        self.assertEqual(vid['summary']['video_url'], self.video_url)
        self.assertEqual(vid['summary']['size'], 12345)
        self.assertIn('en', vid['summary']['transcripts'])
        self.assertFalse(vid['summary']['only_on_web'])
        self.assertEqual(course_outline[1]['summary']['video_url'], self.html5_video_url)
        self.assertEqual(course_outline[1]['summary']['size'], 0)
        self.assertFalse(course_outline[1]['summary']['only_on_web'])
        self.assertEqual(course_outline[1]['path'][2]['name'], self.other_unit.display_name)
        self.assertEqual(course_outline[1]['path'][2]['id'], unicode(self.other_unit.location))
        self.assertEqual(course_outline[2]['summary']['video_url'], self.html5_video_url)
        self.assertEqual(course_outline[2]['summary']['size'], 0)
        self.assertFalse(course_outline[2]['summary']['only_on_web'])

    def test_with_nameless_unit(self):
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.nameless_unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test draft video omega 2 \u03a9"
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        self.assertEqual(course_outline[0]['path'][2]['name'], self.nameless_unit.location.block_id)

    def test_with_video_in_sub_section(self):
        """
        Tests a non standard xml format where a video is underneath a sequential

        We are expecting to return the same unit and section url since there is
        no unit vertical.
        """
        self.login_and_enroll()
        ItemFactory.create(
            parent=self.sub_section,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"video in the sub section"
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        self.assertEqual(len(course_outline[0]['path']), 2)
        section_url = course_outline[0]["section_url"]
        unit_url = course_outline[0]["unit_url"]
        self.assertIn(
            u'courseware/test_factory_section_omega_%CE%A9/test_subsection_omega_%CE%A9',
            section_url

        )
        self.assertTrue(section_url)
        self.assertTrue(unit_url)
        self.assertEqual(section_url, unit_url)

    @ddt.data(
        *itertools.product([True, False], ["video", "problem"])
    )
    @ddt.unpack
    def test_with_split_block(self, is_user_staff, sub_block_category):
        """Test with split_module->sub_block_category and for both staff and non-staff users."""
        self.login_and_enroll()
        self.user.is_staff = is_user_staff
        self.user.save()
        self._setup_split_module(sub_block_category)

        video_outline = self.api_response().data
        num_video_blocks = 1 if sub_block_category == "video" else 0
        self.assertEqual(len(video_outline), num_video_blocks)
        for block_index in range(num_video_blocks):
            self._verify_paths(
                video_outline,
                [
                    self.section.display_name,
                    self.sub_section.display_name,
                    self.unit.display_name,
                    self.split_test.display_name
                ],
                block_index
            )
            self.assertIn(u"split test block", video_outline[block_index]["summary"]["name"])

    def test_with_split_vertical(self):
        """Test with split_module->vertical->video structure."""
        self.login_and_enroll()
        split_vertical_a, split_vertical_b = self._setup_split_module("vertical")

        ItemFactory.create(
            parent=split_vertical_a,
            category="video",
            display_name=u"video in vertical a",
        )
        ItemFactory.create(
            parent=split_vertical_b,
            category="video",
            display_name=u"video in vertical b",
        )

        video_outline = self.api_response().data

        # user should see only one of the videos (a or b).
        self.assertEqual(len(video_outline), 1)
        self.assertIn(u"video in vertical", video_outline[0]["summary"]["name"])
        a_or_b = video_outline[0]["summary"]["name"][-1:]
        self._verify_paths(
            video_outline,
            [
                self.section.display_name,
                self.sub_section.display_name,
                self.unit.display_name,
                self.split_test.display_name,
                u"split test block " + a_or_b
            ],
        )

    def _create_cohorted_video(self, group_id):
        """Creates a cohorted video block, giving access to only the given group_id."""
        video_block = ItemFactory.create(
            parent=self.unit,
            category="video",
            display_name=u"video for group " + unicode(group_id),
        )
        self._setup_group_access(video_block, self.partition_id, [group_id])

    def _create_cohorted_vertical_with_video(self, group_id):
        """Creates a cohorted vertical with a child video block, giving access to only the given group_id."""
        vertical_block = ItemFactory.create(
            parent=self.sub_section,
            category="vertical",
            display_name=u"vertical for group " + unicode(group_id),
        )
        self._setup_group_access(vertical_block, self.partition_id, [group_id])
        ItemFactory.create(
            parent=vertical_block,
            category="video",
            display_name=u"video for group " + unicode(group_id),
        )

    @ddt.data("_create_cohorted_video", "_create_cohorted_vertical_with_video")
    def test_with_cohorted_content(self, content_creator_method_name):
        self.login_and_enroll()
        self._setup_course_partitions(scheme_id='cohort', is_cohorted=True)

        cohorts = []
        for group_id in [0, 1]:
            getattr(self, content_creator_method_name)(group_id)

            cohorts.append(CohortFactory(course_id=self.course.id, name=u"Cohort " + unicode(group_id)))
            link = CourseUserGroupPartitionGroup(
                course_user_group=cohorts[group_id],
                partition_id=self.partition_id,
                group_id=group_id,
            )
            link.save()

        for cohort_index in range(len(cohorts)):
            # add user to this cohort
            add_user_to_cohort(cohorts[cohort_index], self.user.username)

            # should only see video for this cohort
            video_outline = self.api_response().data
            self.assertEqual(len(video_outline), 1)
            self.assertEquals(
                u"video for group " + unicode(cohort_index),
                video_outline[0]["summary"]["name"]
            )

            # remove user from this cohort
            remove_user_from_cohort(cohorts[cohort_index], self.user.username)

        # un-cohorted user should see no videos
        video_outline = self.api_response().data
        self.assertEqual(len(video_outline), 0)

        # staff user sees all videos
        self.user.is_staff = True
        self.user.save()
        video_outline = self.api_response().data
        self.assertEqual(len(video_outline), 2)

    def test_with_hidden_blocks(self):
        self.login_and_enroll()
        hidden_subsection = ItemFactory.create(
            parent=self.section,
            category="sequential",
            hide_from_toc=True,
        )
        unit_within_hidden_subsection = ItemFactory.create(
            parent=hidden_subsection,
            category="vertical",
        )
        hidden_unit = ItemFactory.create(
            parent=self.sub_section,
            category="vertical",
            hide_from_toc=True,
        )
        ItemFactory.create(
            parent=unit_within_hidden_subsection,
            category="video",
            edx_video_id=self.edx_video_id,
        )
        ItemFactory.create(
            parent=hidden_unit,
            category="video",
            edx_video_id=self.edx_video_id,
        )
        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 0)

    def test_language(self):
        self.login_and_enroll()
        video = ItemFactory.create(
            parent=self.nameless_unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test draft video omega 2 \u03a9"
        )

        language_case = namedtuple('language_case', ['transcripts', 'expected_language'])
        language_cases = [
            # defaults to english
            language_case({}, "en"),
            # supports english
            language_case({"en": 1}, "en"),
            # supports another language
            language_case({"lang1": 1}, "lang1"),
            # returns first alphabetically-sorted language
            language_case({"lang1": 1, "en": 2}, "en"),
            language_case({"lang1": 1, "lang2": 2}, "lang1"),
        ]

        for case in language_cases:
            video.transcripts = case.transcripts
            modulestore().update_item(video, self.user.id)
            course_outline = self.api_response().data
            self.assertEqual(len(course_outline), 1)
            self.assertEqual(course_outline[0]['summary']['language'], case.expected_language)

    def test_transcripts(self):
        self.login_and_enroll()
        video = ItemFactory.create(
            parent=self.nameless_unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test draft video omega 2 \u03a9"
        )

        transcript_case = namedtuple('transcript_case', ['transcripts', 'english_subtitle', 'expected_transcripts'])
        transcript_cases = [
            # defaults to english
            transcript_case({}, "", ["en"]),
            transcript_case({}, "en-sub", ["en"]),
            # supports english
            transcript_case({"en": 1}, "", ["en"]),
            transcript_case({"en": 1}, "en-sub", ["en"]),
            # keeps both english and other languages
            transcript_case({"lang1": 1, "en": 2}, "", ["lang1", "en"]),
            transcript_case({"lang1": 1, "en": 2}, "en-sub", ["lang1", "en"]),
            # adds english to list of languages only if english_subtitle is specified
            transcript_case({"lang1": 1, "lang2": 2}, "", ["lang1", "lang2"]),
            transcript_case({"lang1": 1, "lang2": 2}, "en-sub", ["lang1", "lang2", "en"]),
        ]

        for case in transcript_cases:
            video.transcripts = case.transcripts
            video.sub = case.english_subtitle
            modulestore().update_item(video, self.user.id)
            course_outline = self.api_response().data
            self.assertEqual(len(course_outline), 1)
            self.assertSetEqual(
                set(course_outline[0]['summary']['transcripts'].keys()),
                set(case.expected_transcripts)
            )

    @ddt.data(
        ({}, '', [], ['en']),
        ({}, '', ['de'], ['de']),
        ({}, '', ['en', 'de'], ['en', 'de']),
        ({}, 'en-subs', ['de'], ['en', 'de']),
        ({'uk': 1}, 'en-subs', ['de'], ['en', 'uk', 'de']),
        ({'uk': 1, 'de': 1}, 'en-subs', ['de', 'en'], ['en', 'uk', 'de']),
    )
    @ddt.unpack
    @patch('openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled', Mock(return_value=True))
    @patch('xmodule.video_module.transcripts_utils.edxval_api.get_available_transcript_languages')
    def test_val_transcripts_with_feature_enabled(self, transcripts, english_sub, val_transcripts,
                                                  expected_transcripts, mock_get_transcript_languages):
        self.login_and_enroll()
        video = ItemFactory.create(
            parent=self.nameless_unit,
            category="video",
            edx_video_id=self.edx_video_id,
            display_name=u"test draft video omega 2 \u03a9"
        )

        mock_get_transcript_languages.return_value = val_transcripts
        video.transcripts = transcripts
        video.sub = english_sub
        modulestore().update_item(video, self.user.id)

        course_outline = self.api_response().data
        self.assertEqual(len(course_outline), 1)
        self.assertItemsEqual(course_outline[0]['summary']['transcripts'].keys(), expected_transcripts)


@attr(shard=2)
class TestTranscriptsDetail(TestVideoAPITestCase, MobileAuthTestMixin, MobileCourseAccessTestMixin,
                            TestVideoAPIMixin, MilestonesTestCaseMixin):
    """
    Tests for /api/mobile/v0.5/video_outlines/transcripts/{course_id}..
    """
    REVERSE_INFO = {'name': 'video-transcripts-detail', 'params': ['course_id']}

    def setUp(self):
        super(TestTranscriptsDetail, self).setUp()
        self.video = self._create_video_with_subs()

    def reverse_url(self, reverse_args=None, **kwargs):
        reverse_args = reverse_args or {}
        reverse_args.update({
            'block_id': self.video.location.block_id,
            'lang': kwargs.get('lang', 'en'),
        })
        return super(TestTranscriptsDetail, self).reverse_url(reverse_args, **kwargs)

    def test_incorrect_language(self):
        self.login_and_enroll()
        self.api_response(expected_response_code=404, lang='pl')

    def test_transcript_with_unicode_file_name(self):
        self.video = self._create_video_with_subs(custom_subid=u'你好')
        self.login_and_enroll()
        self.api_response(expected_response_code=200, lang='en')

    @patch(
        'openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled',
        Mock(return_value=True),
    )
    @patch(
        'xmodule.video_module.transcripts_utils.edxval_api.get_available_transcript_languages',
        Mock(return_value=['uk']),
    )
    @patch('xmodule.video_module.transcripts_utils.edxval_api.get_video_transcript_data')
    def test_val_transcript(self, mock_get_video_transcript_content):
        """
        Tests transcript retrieval view with val transcripts.
        """
        mock_get_video_transcript_content.return_value = {
            'content': json.dumps({
                'start': [10],
                'end': [100],
                'text': [u'Hi, welcome to Edx.'],
            }),
            'file_name': 'edx.sjson'
        }

        self.login_and_enroll()
        # Now, make request to retrieval endpoint
        response = self.api_response(expected_response_code=200, lang='uk')

        # Expected headers
        expected_content = u'0\n00:00:00,010 --> 00:00:00,100\nHi, welcome to Edx.\n\n'
        expected_headers = {
            'Content-Disposition': 'attachment; filename="edx.srt"',
            'Content-Type': 'application/x-subrip; charset=utf-8'
        }
        # Assert the actual response
        self.assertEqual(response.content, expected_content)
        for attribute, value in expected_headers.iteritems():
            self.assertEqual(response.get(attribute), value)

    @patch(
        'openedx.core.djangoapps.video_config.models.VideoTranscriptEnabledFlag.feature_enabled',
        Mock(return_value=False),
    )
    @patch(
        'xmodule.video_module.transcripts_utils.edxval_api.get_available_transcript_languages',
        Mock(return_value=['uk']),
    )
    def test_val_transcript_feature_disabled(self):
        """
        Tests transcript retrieval view with val transcripts when
        the corresponding feature is disabled.
        """
        self.login_and_enroll()
        # request to retrieval endpoint will result in 404 as val transcripts are disabled.
        self.api_response(expected_response_code=404, lang='uk')
