"""
Serializer for video outline
"""
from rest_framework.reverse import reverse

from xmodule.modulestore.mongo.base import BLOCK_TYPES_WITH_CHILDREN
from courseware.access import has_access

from edxval.api import (
    get_video_info_for_course_and_profile, ValInternalError
)


class BlockOutline(object):
    """
    Serializes course videos, pulling data from VAL and the video modules.
    """
    def __init__(self, course_id, start_block, block_types, request):
        """Create a BlockOutline using `start_block` as a starting point."""
        self.start_block = start_block
        self.block_types = block_types
        self.course_id = course_id
        self.request = request  # needed for making full URLS
        self.local_cache = {}
        try:
            self.local_cache['course_videos'] = get_video_info_for_course_and_profile(
                unicode(course_id), "mobile_low"
            )
        except ValInternalError:  # pragma: nocover
            self.local_cache['course_videos'] = {}

    def __iter__(self):
        child_to_parent = {}
        stack = [self.start_block]

        # path should be optional
        def path(block):
            """path for block"""
            block_path = []
            while block in child_to_parent:
                block = child_to_parent[block]
                if block is not self.start_block:
                    block_path.append({
                        # to be consistent with other edx-platform clients, return the defaulted display name
                        'name': block.display_name_with_default,
                        'category': block.category,
                        'id': unicode(block.location)
                    })
            return reversed(block_path)

        def find_urls(block):
            """
            Find the section and unit urls for a block.

            Returns:
                unit_url, section_url:
                    unit_url (str): The url of a unit
                    section_url (str): The url of a section

            """
            block_path = []
            while block in child_to_parent:
                block = child_to_parent[block]
                block_path.append(block)

            block_list = list(reversed(block_path))
            block_count = len(block_list)

            chapter_id = block_list[1].location.block_id if block_count > 1 else None
            section = block_list[2] if block_count > 2 else None
            position = None

            #position is found traversing the section block
            if block_count > 3:
                position = 1
                for block in section.children:
                    if block.name == block_list[3].url_name:
                        break
                    position += 1

            if chapter_id is None:
                no_chapter_url = reverse(
                    "courseware",
                    kwargs=dict(
                        course_id=unicode(self.course_id),
                    ),
                    request=self.request
                )
                return no_chapter_url, no_chapter_url
            elif section is None:
                no_section_url = reverse(
                    "courseware_chapter",
                    kwargs=dict(
                        course_id=unicode(self.course_id),
                        chapter=chapter_id
                    ),
                    request=self.request
                )
                return no_section_url, no_section_url
            elif position is None:
                no_position_url = reverse(
                    "courseware_section",
                    kwargs=dict(
                        course_id=unicode(self.course_id),
                        chapter=chapter_id,
                        section=section.url_name
                    ),
                    request=self.request
                )
                return no_position_url, no_position_url
            else:
                section_url = reverse(
                    "courseware_section",
                    kwargs=dict(
                        course_id=unicode(self.course_id),
                        chapter=chapter_id,
                        section=section.url_name
                    ),
                    request=self.request
                )
                unit_url = reverse(
                    "courseware_position",
                    kwargs=dict(
                        course_id=unicode(self.course_id),
                        chapter=chapter_id,
                        section=section.url_name,
                        position=position
                    ),
                    request=self.request
                )
                return unit_url, section_url

        user = self.request.user

        while stack:
            curr_block = stack.pop()

            if curr_block.hide_from_toc:
                # For now, if the 'hide_from_toc' setting is set on the block, do not traverse down
                # the hierarchy.  The reason being is that these blocks may not have human-readable names
                # to display on the mobile clients.
                # Eventually, we'll need to figure out how we want these blocks to be displayed on the
                # mobile clients.  As, they are still accessible in the browser, just not navigatable
                # from the table-of-contents.
                continue

            if curr_block.location.block_type in self.block_types:
                if not has_access(user, 'load', curr_block, course_key=self.course_id):
                    continue

                summary_fn = self.block_types[curr_block.category]
                block_path = list(path(curr_block))
                unit_url, section_url = find_urls(curr_block)

                yield {
                    "path": block_path,
                    "named_path": [b["name"] for b in block_path],
                    "unit_url": unit_url,
                    "section_url": section_url,
                    "summary": summary_fn(self.course_id, curr_block, self.request, self.local_cache)
                }

            def parent_or_requested_block_type(usage_key):
                """
                Returns whether the usage_key's block_type is one of self.block_types or a parent type.
                """
                return (
                    usage_key.block_type in self.block_types or
                    usage_key.block_type in BLOCK_TYPES_WITH_CHILDREN
                )

            if curr_block.has_children:
                for block in reversed(curr_block.get_children(usage_key_filter=parent_or_requested_block_type)):
                    stack.append(block)
                    child_to_parent[block] = curr_block


def video_summary(course, course_id, video_descriptor, request, local_cache):
    """
    returns summary dict for the given video module
    """
    # First try to check VAL for the URLs we want.
    val_video_info = local_cache['course_videos'].get(video_descriptor.edx_video_id, {})
    if val_video_info:
        video_url = val_video_info['url']
    # Then fall back to VideoDescriptor fields for video URLs
    elif video_descriptor.html5_sources:
        video_url = video_descriptor.html5_sources[0]
    else:
        video_url = video_descriptor.source

    # If we have the video information from VAL, we also have duration and size.
    duration = val_video_info.get('duration', None)
    size = val_video_info.get('file_size', 0)

    # Transcripts...
    transcript_langs = video_descriptor.available_translations(verify_assets=False)

    transcripts = {
        lang: reverse(
            'video-transcripts-detail',
            kwargs={
                'course_id': unicode(course_id),
                'block_id': video_descriptor.scope_ids.usage_id.block_id,
                'lang': lang
            },
            request=request,
        )
        for lang in transcript_langs
    }

    return {
        "video_url": video_url,
        "video_thumbnail_url": None,
        "duration": duration,
        "size": size,
        "name": video_descriptor.display_name,
        "transcripts": transcripts,
        "language": video_descriptor.get_default_transcript_language(),
        "category": video_descriptor.category,
        "id": unicode(video_descriptor.scope_ids.usage_id),
    }
