# -*- coding: utf-8 -*-
from elasticsearch import RequestError as ElasticsearchRequestError
from elasticsearch import TransportError as ElasticsearchTransportError
from flask_restful import abort
from werkzeug.exceptions import NotFound

from distribution import app
from distribution.models import ValidationError
from . import BaseManager


class SitemapURLManager(BaseManager):
    index = app.config.get('ELASTICSEARCH_SITEMAP_INDEX_NAME', 'distribution_sitemap')

    def bulk_save(self, documents, errors, domain=None):
        localizations_models = []
        for item in documents:
            try:
                localizations_models += item.process_localizations(domain)
            except ValidationError as e:
                documents.remove(item)
                errors.append({
                    'id': item.key,
                    'domain': domain,
                    'content_type': item.data['content_type'],
                    'uri': item.data['url'],
                    'error': e.message,
                })
        documents += localizations_models
        super(SitemapURLManager, self).bulk_save(documents, errors)

    def search_by_field(self, field, value, filter_future_content=True):
        query_string = '{}:"{}"'.format(field, value)
        if filter_future_content:
            query_string += " AND publication_datetime:[* TO now]"

        query = {
            'query': {
                'query_string': {
                    'query': query_string
                }
            }
        }

        try:
            result = self.backend.client.search(self.index, '', query)
        except (ElasticsearchRequestError, ElasticsearchTransportError) as e:
            app.logger.exception(e)
            abort(400, message='Invalid Request')
        hits = result['hits']['hits']
        if not hits:
            raise NotFound()
        return self.cast_to_models(hits)

    def build_search_query(self, *args, **kwargs):

        parameters = self._build_query_arguments(kwargs)
        query = {
            'query': {
                'bool': {
                    'must': {
                        'bool': {
                            'must': [],
                            'must_not': []
                        }
                    },
                    "filter": {
                        "bool": {
                            "must": [
                                {
                                    'term': {
                                        'meta.is_deleted': parameters['deleted']
                                    }
                                }
                            ],
                            "must_not": []
                        }
                    }
                }
            }
        }

        if kwargs.get('page', None):
            self._add_sorting(query)
            self._add_pagination(query, parameters)

        if parameters['domain']:
            if parameters['subdomains']:
                self._search_by_subdomain(query, parameters)
            else:
                self._search_by_domain(query, parameters)
            self._build_query_datetime(query, parameters, 'publication_datetime',
                                       from_range='gte' if parameters['publication_datetime__from'] else '')

        if kwargs.get('genres', None):
            self._search_by_taxonomy_term(query, 'genres', kwargs['genres'])

        if parameters.get('size', None):
            query['size'] = parameters.get('size')

        return query

    @staticmethod
    def _build_query_arguments(parameters):

        arguments = {
            'limit': app.config['SITEMAP_MAX_ROWS_LIMIT'],
            'publication_datetime__to': 'now',
            'publication_datetime__from': parameters.get('publication_datetime__from', ''),
            'domain': parameters.get('domain', None),
            'subdomains': parameters.get('subdomains', None),
            'page': parameters.get('page', None),
            'deleted': parameters.get('deleted', False),
            'size': parameters.get('size', None),
        }

        return arguments

    def _add_pagination(self, query, arguments):
        page = int(arguments['page'])
        limit = arguments['limit']

        query['from'] = (page-1) * limit
        query['size'] = limit

        if (query['from'] + query['size']) > self.MAX_RESULT_WINDOW:
            abort(400, message='Pagination Limit exceeded')

    @staticmethod
    def _add_sorting(query):
        query['sort'] = {
            'publication_datetime': {
                'order': 'desc',
                'unmapped_type': "date",
            }
        }

    @staticmethod
    def _build_query_datetime(query, arguments, field, from_range='gte', to_range='lte'):
        query_range = {
            'range': {
                field: {}
            }
        }

        if from_range:
            query_range['range'][field][from_range] = arguments[field + '__from']
        if to_range:
            query_range['range'][field][to_range] = arguments[field + '__to']

        query['query']['bool']['must']['bool']['must'].append(query_range)

    @staticmethod
    def _search_by_domain(query, arguments):
        query['query']['bool']['must']['bool']['must'].append({
            'match_phrase': {
                'url': arguments['domain']
            }
        })

    @staticmethod
    def _search_by_subdomain(query, arguments ):
        aux_query = {
            'bool': {
                'should': [

                ]
            }
        }
        for subdomain in arguments['subdomains']:
            aux_query['bool']['should'].append({
                'match_phrase': {
                    'url':  '{0}/{1}'.format(arguments['domain'], subdomain),
                }
            })

        query['query']['bool']['must']['bool']['must'].append(aux_query)


    @staticmethod
    def _search_by_taxonomy_term(query, term, value):
        query['query']['bool']['must']['bool']['must'].append({
            'bool': {
                'minimum_should_match': 1,
                'should': [
                    {
                        'match_phrase': {
                            term: value
                        }
                    }
                ]
            }
        })
