# -*- coding: utf-8 -*-
from datetime import datetime
from werkzeug.exceptions import NotFound

from distribution import utils, app
from . import Model, ValidationError
from .taxonomy import TaxonomyTopic
from ..managers.feed import FeedItemManager
from ..schemas.feed import FeedSchema


class FeedItem(Model):
    excluded_serializers = ['rss']
    manager_class = FeedItemManager
    schema = FeedSchema()
    default_fields = [
        "abstract",
        "sources",
        "title",
        "last_modified_datetime",
        "publication_datetime"
    ]

    def __init__(self, data, domain=None, validate=True, **kwargs):
        data = self._initialize_data(data, domain)
        super(FeedItem, self).__init__(data, validate)

    def _validate_taxonomy_topics(self):
        for topic_type in app.config['TAXONOMY_TOPIC_TYPES']:
            # Remove duplicates keeping the order
            if topic_type in self.data:
                seen = set()
                self.data[topic_type] = [seen.add(x) or x for x in self.data[topic_type] if
                                         x not in seen]
                for uuid in self.data[topic_type][:]:
                    try:
                        TaxonomyTopic.manager.get(uuid)
                    except NotFound:

                        app.logger.warning(u'TaxonomyTopic of type {} with UUID {} not found for '
                                           'FeedItem {}'.format(topic_type, uuid, self.key))
                        self.data[topic_type].remove(uuid)

                if 'unknown_terms' in self.data:
                    for name in self.data['unknown_terms'][topic_type]:
                        self._search_and_append_taxonomy_topic(name, topic_type)

        if 'unknown_terms' in self.data:
            for name in self.data['unknown_terms']['']:
                self._search_and_append_taxonomy_topic(name, None)

            del self.data['unknown_terms']

    def get_language_dict(self):
        """
        Retrieves a dict of languages of the feed item
        :return: the dictionary of languages that the feed item contains
        """
        return {'id': self.data['id'], 'language': self.data['language']}

    def validate(self, data):
        super(FeedItem, self).validate(data)
        self._validate_taxonomy_topics()
        self.localization_root = self.find_localization_root()

    def _search_and_append_taxonomy_topic(self, name, topic_type):
        topics = TaxonomyTopic.manager.search_by_name_and_type(name, topic_type)

        msg = u'TaxonomyTopic (type={},name={},uuid={{}}) for FeedItem(key={}) {{}}'.format(
            topic_type or 'unspecified', name, self.key)
        if len(topics) == 1:
            topic_uuid = topics[0].data['uuid']
            app.logger.info(msg.format(topic_uuid, 'resolved'))
            self.data[topics[0].data['topic_type']].append(topic_uuid)
        else:
            app.logger.info(msg.format(
                None, 'not found' if len(topics) == 0 else 'multiple items found'))

    @property
    def domain(self):
        return self.data['meta']['domain']

    @property
    def localization_root(self):
        return self.data['meta'].get('localization_root', None)

    @localization_root.setter
    def localization_root(self, value):
        self.data['meta']['localization_root'] = value

    @property
    def last_update(self):
        return self.data['meta']['last_update']

    @property
    def key(self):
        return self.data['id']

    def is_deleted(self):
        return self.data['meta']['is_deleted']

    def get(self, key, default=None):
        return self.data.get(key, default)

    def get_children(self, root_id):
        try:
            return self.manager.search_by_field('meta.localization_root', root_id)
        except NotFound:
            return []

    @property
    def localizations(self):
        if not hasattr(self, '_localizations'):
            self._localizations = []

            if self.localization_root:
                try:
                    children = self.get_children(self.localization_root)
                    self._localizations.extend([o.get_language_dict() for o in children if o.key != self.key])
                    parent = self.manager.get_by_field('id', self.localization_root)
                    self._localizations.append(parent.get_language_dict())
                except NotFound:
                    app.logger.exception('Wrong parent id({}) in article with id: {}'.format(
                                         self.data['parent'], self.data['id']))
            else:
                children = self.get_children(self.key)
                self._localizations.extend([o.get_language_dict() for o in children])

        return self._localizations

    def find_localization_root(self, recursion_ids=None):
        if not recursion_ids:
            recursion_ids = []

        if self.data.get('parent', None):
            try:
                parent = self.manager.get_by_field('id', self.data['parent'])
                if not parent.data.get('parent', None):
                    return parent.key
                if parent.key in recursion_ids:
                    raise ValidationError('Wrong parent id({}), in article with id: {} . Infinite '
                                          'loop found'.format(self.data['parent'], self.data['id']))
                recursion_ids.append(parent.key)
                return parent.find_localization_root(recursion_ids)
            except NotFound:
                app.logger.exception('Parent id ({}) not found, in article with id: {}'.format(
                                     self.data['parent'], self.data['id']))
        return None

    def _initialize_data(self, data, domain):
        now_utc = utils.utc_date_to_string(datetime.utcnow())
        data.setdefault('meta', {})
        data['meta'].setdefault('created_at', now_utc)
        data['meta'].setdefault('last_update', now_utc)
        data['meta'].setdefault('is_deleted', False)
        data['meta'].setdefault('domain', domain)

        return data
