from .base import (
    CERBERUS_RULE_ARTICLE_SCHEMA,
    CERBERUS_RULE_OPTIONAL_STRING,
    CERBERUS_RULE_PHOTO_SCHEMA,
    CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
    CERBERUS_RULE_SCHEDULE_SCHEMA,
    CERBERUS_RULE_SERIES_SCHEMA,
    Schema,
    AnimalFactsReferenceSchema,
    ImageSchema,
    VideoSchema,
    ImageGallerySchema,
    PullQuoteSchema,
    YouTubeSchema,
    AudioSchema,
    InteractiveSchema,
)
from .feed import FeedSchema


# Rules above will be dropped after WP is gone.
DEPRECATED_CERBERUS_RULE_IMAGE_SCHEMA = {
    'uri': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
    'caption': CERBERUS_RULE_OPTIONAL_STRING,
    'credit': CERBERUS_RULE_OPTIONAL_STRING
}

DEPRECATED_CERBERUS_RULE_VIDEO_SCHEMA = {
    'uri': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
    'duration': {'type': 'float', 'nullable': True, 'default': None},
    'bitrate': {'type': 'float', 'nullable': True, 'default': None},
    'frame_rate': {'type': 'float', 'nullable': True, 'default': None},
    'language': CERBERUS_RULE_OPTIONAL_STRING,
    'format': CERBERUS_RULE_OPTIONAL_STRING,
    'content_type': CERBERUS_RULE_OPTIONAL_STRING,
    'expression': CERBERUS_RULE_OPTIONAL_STRING,
    'height': {'type': 'integer', 'nullable': True, 'default': None},
    'width': {'type': 'integer', 'nullable': True, 'default': None},
    'file_size': {'type': 'integer', 'nullable': True, 'default': None},
    'audio_channels': {'type': 'integer', 'nullable': True, 'default': None},
    'audio_sample_rate': {'type': 'integer', 'nullable': True, 'default': None},
    'default': {'type': 'boolean', 'default': False}
}


class Component(Schema):
    content_type = None
    object_rule = CERBERUS_RULE_REQUIRED_NONEMPTY_STRING

    def __init__(self, *args, **kwargs):
        super(Component, self).__init__(*args, **kwargs)
        if self.content_type is None:
            raise Exception('Invalid Component: content_type must be set.')
        self['content_type'] = {
            'type': 'string',
            'required': True,
            'allowed': [self.content_type]
        }
        self[self.content_type] = self.object_rule


class TextComponent(Component):
    content_type = 'text'


class ExcerptComponent(Component):
    content_type = 'excerpt'
    object_rule = {
        'type': 'dict',
        'schema': {
            'excerpt': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING
        }
    }


class ImageComponent(Component):
    content_type = 'image'
    object_rule = {
        'type': 'dict',
        'schema': ImageSchema()
    }


class ImageGroupComponent(Component):
    content_type = 'image_group'
    object_rule = {
        'type': 'dict'
    }


class VideoComponent(Component):
    content_type = 'video'
    object_rule = {
        'type': 'dict',
        'schema': VideoSchema()
    }


class ImageGalleryComponent(Component):
    content_type = 'image_gallery'
    object_rule = {
        'type': 'dict',
        'schema': ImageGallerySchema()
    }


class GalleryComponent(Component):
    """TO BE DEPRECATED"""
    content_type = 'gallery'
    object_rule = {
        'type': 'list',
        'schema': ImageSchema()
    }


class PullQuoteComponent(Component):
    content_type = 'pull_quote'
    object_rule = {
        'type': 'dict',
        'schema': PullQuoteSchema()
    }


class AnimalFactsComponent(Component):
    content_type = 'animal_facts'
    object_rule = {
        'type': 'dict',
        'schema': AnimalFactsReferenceSchema()
    }


class YouTubeComponent(Component):
    content_type = 'youtube_video'
    object_rule = {
        'type': 'dict',
        'schema': YouTubeSchema()
    }


class AudioComponent(Component):
    content_type = 'audio'
    object_rule = {
        'type': 'dict',
        'schema': AudioSchema()
    }


class InteractiveComponent(Component):
    content_type = 'interactive'
    object_rule = {
        'type': 'dict',
        'schema': InteractiveSchema()
    }


class AltBodiesSchema(Schema):  # pragma: no cover
    COMPONENTS = [
        TextComponent(),
        ExcerptComponent(),
        PullQuoteComponent(),
        ImageComponent(),
        ImageGalleryComponent(),
        ImageGroupComponent(),
        VideoComponent(),
        YouTubeComponent(),
        AudioComponent(),
        InteractiveComponent(),
    ]

    def __init__(self, content_type, *args, **kwargs):
        super(AltBodiesSchema, self).__init__(*args, **kwargs)
        self['text'] = {
            'type': 'dict',
            'required': False,
            'nullable': True,
            'schema': {
                'body': CERBERUS_RULE_OPTIONAL_STRING,
            }
        }

        self['structured'] = {
            'type': 'dict',
            'schema': {
                'content': {
                    'type': 'list',
                    'schema': {
                        'type': 'dict',
                        'anyof_schema': self.COMPONENTS
                    }
                },
            }
        }
        if content_type == 'article:image_gallery':
            self['structured']['schema']['content']['validator'] = [
                self.has_component_validator_factory('image_gallery')]
        elif content_type == 'article:reference':
            self['structured']['schema']['content']['validator'] = [
                self.has_component_validator_factory('animal_facts')]
            self['structured']['schema']['content']['schema']['anyof_schema'] += [
                AnimalFactsComponent(),
            ]
        else:
            self['structured']['schema']['content']['schema']['anyof_schema'] += [
                GalleryComponent(),
            ]

    @staticmethod
    def has_component_validator_factory(content_type):
        def _has_component(field, value, error):
            image_galleries = [x for x in value if x['content_type'] == content_type]
            if not image_galleries:
                error(field, "Must contain an image_gallery component.")
        return _has_component


class ArticleSchema(FeedSchema):
    def __init__(self, content_type=None, strict=False):
        super(ArticleSchema, self).__init__()
        # ********* Media assets *********
        self['images'] = {
            'type': 'list',
            'default': [],
            'schema': {
                'type': 'dict',
                'schema': (DEPRECATED_CERBERUS_RULE_IMAGE_SCHEMA if content_type == 'article:post'
                           else ImageSchema())  # Added for compatibility with wp consumers
            }
        }
        self['photo_galleries'] = {
            'type': 'list',
            'default': [],
            'schema': {
                'type': 'list',
                'schema': {
                    'type': 'dict',
                    'schema': (DEPRECATED_CERBERUS_RULE_IMAGE_SCHEMA
                               if content_type == 'article:post'
                               else ImageSchema())  # Added for compatibility with wp consumers
                }
            }
        }
        self['videos'] = {
            'type': 'list',
            'default': [],
            'schema': {
                'type': 'dict',
                'schema': (DEPRECATED_CERBERUS_RULE_VIDEO_SCHEMA if content_type == 'article:post'
                           else VideoSchema())  # Added for compatibility with wp consumers
            }
        }
        # ********* Content *********
        self['contributors'] = {
            'type': 'list',
            'default': [],
            'schema': {
                'type': 'dict',
                'schema': {
                    'role': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
                    'name': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
                    'order': {'type': 'integer', 'default': 0}
                }
            }
        }

        if strict:
            self['alt_bodies'] = {
                'type': 'dict',
                'nullable': True,
                'default': {},
                'schema': AltBodiesSchema(content_type=content_type)
            }

        self['body'] = CERBERUS_RULE_OPTIONAL_STRING
        # ********* Extra fields *********
        self['extra_fields'] = {
            'type': 'dict',
            'default': {},
            'schema': {
                'photo': CERBERUS_RULE_PHOTO_SCHEMA,
                'schedule': CERBERUS_RULE_SCHEDULE_SCHEMA,
                'series': CERBERUS_RULE_SERIES_SCHEMA,
                'article': CERBERUS_RULE_ARTICLE_SCHEMA
            }
        }
        self['kickers'] = {
            'type': 'list',
            'nullable': True,
            'default': None,
            'schema': {
                'name': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
                'url': CERBERUS_RULE_REQUIRED_NONEMPTY_STRING,
            }
        }
