"""
Serializers for Course Blocks related return objects.
"""
from rest_framework import serializers
from rest_framework.reverse import reverse

from .transformers import SUPPORTED_FIELDS


class BlockSerializer(serializers.Serializer):  # pylint: disable=abstract-method
    """
    Serializer for single course block
    """
    def _get_field(self, block_key, transformer, field_name, default):
        """
        Get the field value requested.  The field may be an XBlock field, a
        transformer block field, or an entire tranformer block data dict.
        """
        if transformer is None:
            value = self.context['block_structure'].get_xblock_field(block_key, field_name)
        elif field_name is None:
            value = self.context['block_structure'].get_transformer_block_data(block_key, transformer)
        else:
            value = self.context['block_structure'].get_transformer_block_field(block_key, transformer, field_name)

        return value if (value is not None) else default

    def to_representation(self, block_key):
        """
        Return a serializable representation of the requested block
        """
        # create response data dict for basic fields
        data = {
            'id': unicode(block_key),
            'lms_web_url': reverse(
                'jump_to',
                kwargs={'course_id': unicode(block_key.course_key), 'location': unicode(block_key)},
                request=self.context['request'],
            ),
            'student_view_url': reverse(
                'courseware.views.render_xblock',
                kwargs={'usage_key_string': unicode(block_key)},
                request=self.context['request'],
            ),
        }

        # add additional requested fields that are supported by the various transformers
        for supported_field in SUPPORTED_FIELDS:
            if supported_field.requested_field_name in self.context['requested_fields']:
                field_value = self._get_field(
                    block_key,
                    supported_field.transformer,
                    supported_field.block_field_name,
                    supported_field.default_value,
                )
                if field_value is not None:
                    # only return fields that have data
                    data[supported_field.serializer_field_name] = field_value

        if 'children' in self.context['requested_fields']:
            children = self.context['block_structure'].get_children(block_key)
            if children:
                data['children'] = [unicode(child) for child in children]

        return data


class BlockDictSerializer(serializers.Serializer):  # pylint: disable=abstract-method
    """
    Serializer that formats a BlockStructure object to a dictionary, rather
    than a list, of blocks
    """
    root = serializers.CharField(source='root_block_usage_key')
    blocks = serializers.SerializerMethodField()

    def get_blocks(self, structure):
        """
        Serialize to a dictionary of blocks keyed by the block's usage_key.
        """
        return {
            unicode(block_key): BlockSerializer(block_key, context=self.context).data
            for block_key in structure
        }
