import uuid

from werkzeug.exceptions import NotFound

from distribution import app
from distribution.models import ValidationError
from .feed import FeedItem
from ..managers.sitemap import SitemapURLManager
from ..schemas.sitemap_url import SitemapURLSchema


class SitemapURL(FeedItem):
    manager_class = SitemapURLManager
    schema = SitemapURLSchema()
    default_fields = [
        "title",
        "genres",
        "last_modified_datetime",
        "publication_datetime",
        "images",
        "language"
    ]

    def process_localizations(self, domain):
        items = []
        # These validations are here and not in the __init__ function to avoid an infinite loop
        self.validate_item_localization()
        localizations = self.validate_localizations()
        for localization in localizations:
            if 'temp_item' in localization:
                item_data = localization['temp_item'].data
                item_data['parent'] = self.key
            else:
                item_data = {
                    'id': '{}:{}'.format(self.data['meta']['domain'], str(uuid.uuid4())),
                    'url': localization['url'],
                    'language': localization['language'],
                    'parent': self.key,
                    'title': self.data['title'],
                    'publication_datetime': self.data['publication_datetime'],
                    'last_modified_datetime': self.data['last_modified_datetime'],
                    'content_type': self.data['content_type'],
                }
            items.append(SitemapURL(item_data, domain))
        # We don't want to save the localization information
        del self.data['localizations']
        return items

    def validate_item_localization(self):
        """
        Validate if the parent already have a localization with the same language but a different
        url
        """
        try:
            for localization in self.localizations:
                if localization['language'] == self.data['language'] and \
                                localization['id'] != self.data['id']:
                    raise ValidationError('SitemapURL id ({}), Parent id ({}) already have a '
                                          'localization for that language and article'
                                          .format(self.data['id'], self.data['parent']))
        except NotFound:
            app.logger.exception('Parent id ({}) not found, in article with id: {}'.format(
                self.data['parent'], self.data['id']))

    def validate_localizations(self):
        for localization in self.data['localizations']:
            self.validate_localization(localization)
        return self.data['localizations']

    def validate_localization(self, localization):

        item_localizations = self.localizations
        item_localizations.append(self.get_language_dict())

        # Verify that if the language already exist in the element localizations, it should be the
        # same that the one in the localization
        for item_localization in item_localizations:
            if item_localization['language'] == localization['language'] and \
                            item_localization['url'] != localization['url']:
                raise ValidationError('Could not process item with id {}, there is already another '
                                      'element with the same language'.format(self.key))

        try:
            item = self.manager.get_by_field('url', localization['url'])
        except NotFound:
            return

        # If the item exist but the language is not the same that the localization,
        # raise an exception
        if localization['language'] != item.data['language']:
            raise ValidationError('Could not process item with id {}, an existing element with '
                                  'same URL has a different language'.format(self.key))

        # To avoid requesting to ElasticSearch again we save the item on a temporal variable
        if item:
            localization['temp_item'] = item

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

    def get_language_dict(self):
        """
        Return the hreflang required info for the sitemap
        :return: Dict with the id, language and url of the sitemap url
        """
        return {'id': self.data['id'], 'language': self.data['language'], 'url': self.data['url']}
