# -*- coding: utf-8 -*-

import io
import json
import os
import uuid
from copy import deepcopy

from dateutil.parser import parse
from mock import patch
from werkzeug.exceptions import NotFound

from distribution.models.feed import FeedItem
from distribution.models.sitemap_url import SitemapURL

BASE_DIR = os.path.dirname(__file__)
fixtures = {}


def reader(path):
    with io.open(path, 'r', encoding='utf-8') as fh:
        return fh.read()


def get_json(fixture):
    path = os.path.join(BASE_DIR, 'fixtures', fixture)

    if not fixtures.get(path):
        fixtures[path] = reader(path)

    return json.loads(fixtures[path])


def get_sitemap_mock_data():
    return get_json('sitemapURL_mock_data.json')


def get_localization_mock_data():
    return get_json('localization_mock_data.json')


def get_sitemap_localization_mock_data():
    return get_json('sitemap_url_localization_mock_data.json')


def get_sitemap_news_mock_data():
    return get_json('sitemap_url_news_mock_data.json')


def get_consumer_post_data():
    return get_json('consumer_post_data.json')


def get_consumer_validate_data():
    return get_json('consumer_validate_data.json')


def get_consumer_delete_data():
    return get_json('consumer_delete_data.json')


def get_stored_data():
    return get_json('stored_data.json')


def get_stored_role_data():
    return get_json('role_stored_data.json')


def get_stored_apiusers_data():
    return get_json('apiuser_stored_data.json')


def model_to_cast(data):
    if len(data) > 0:
        return SitemapURL if data[0]['content_type'] == 'sitemap:url' else FeedItem
    else:
        return ''


def get_stored_item_by_id(data, key, value, validate=True):
    model = model_to_cast(data)
    for element in data:
        if element[key] == value:
            return model(element, 'awesome-project', validate=validate)
    raise NotFound()


def bulk_save_items(data, items):
    for item in items:
        temp_item = None
        for stored_item in data:
            if item.key == stored_item['id']:
                temp_item = stored_item
                break
        if temp_item:
            temp_item.update(item.data)
        else:
            data.append(item.data)


def get_stored_element_children(data, root_id):
    model = model_to_cast(data)
    return [model(x, 'awesome-project')
            for x in data if x['meta']['localization_root'] == root_id]


def wrap_search_response(response, model_type="sitemapurl"):
    """
    Wrap the result of the search similar to how elastic do
    """
    return {
        "hits": {
            "hits": [{'_source': item, '_type': model_type} for item in response],
            "total": len(response)
        }
    }


def wrap_empty_search_response():
    """
    Wrap the result of an empty search similar to how elastic do
    """
    return {
        "hits": {
            "hits": [],
            "total": 0
        }
    }


def get_stored_elements_for_sitemap(data, query, base_date):
    """
    Only works for sitemap tests

    Mock function of the search function of the elastic client
    """

    data_copy = deepcopy(data)
    sorted_data = sorted(data_copy, key=lambda k: parse(k['publication_datetime']), reverse=True)

    domain = query['query']['bool']['must']['bool']['must'][0]['match_phrase']['url']

    result = [sitemap for sitemap in sorted_data
              if domain in sitemap['url'] and
              parse(sitemap['publication_datetime']) < base_date]

    if query.get('from') and query.get('from') > len(result):
        return wrap_search_response([])

    result = result[query['from']:] if query.get('from') + query.get('size') > len(result) \
        else result[query['from']:query['size']]

    return wrap_search_response(result)


def get_stored_item(regenerate_id=False, domain='news', deleted=False, with_meta=True, **kwargs):
    item = get_stored_data()[0]

    item.update(kwargs)
    item['meta']['is_deleted'] = deleted
    item['meta']['domain'] = domain

    if regenerate_id:
        item['id'] = str(uuid.uuid1())

    if not with_meta:
        item.pop('meta')

    return item


def create_feed_item(data):
    with patch('distribution.models.taxonomy.TaxonomyTopic.manager.get', return_value=None):
        return FeedItem(data, validate=False)


def get_attr_owner(obj, attr):
    return next(owner for owner in [obj] + obj.__class__.mro()
                if attr in owner.__dict__)
