# -*- coding: utf-8 -*-
'''Taxonomy Manager tests.'''
from unittest import TestCase

from mock import Mock, patch, call
from test.utils import (
    wrap_search_response,
    wrap_empty_search_response,
    get_sitemap_mock_data
)
from werkzeug.exceptions import NotFound, HTTPException
from elasticsearch import RequestError as ElasticsearchRequestError
from distribution.models.sitemap_url import SitemapURL
from distribution.utils.paginator import Paginator
from distribution.models.taxonomy import TaxonomyTopic


class TaxonomyTopicManagerTestCase(TestCase):
    LOCATION_TOPICS = {
        'root': {
            'uuid': 'root',
            'children': [
                'child1',
                'child2'
            ]
        },
        'child1': {
            'uuid': 'child1',
            'children': [
                'grandChild1'
            ]
        },
        'child2': {
            'uuid': 'child2',
            'children': [
                'grandChild2'
            ]
        },
        'grandChild1': {
            'uuid': 'grandChild1',
            'children': []
        },
        'grandChild2': {
            'uuid': 'grandChild2',
            'children': []
        }
    }

    def mget_side_effect(self, uuids):
        topics = []
        for uuid in uuids:
            topic = self.LOCATION_TOPICS.get(uuid)
            if topic:
                topic_mock = Mock()
                topic_mock.data = topic
                topics.append(topic_mock)
        return topics

    @patch('distribution.managers.BaseManager.mget')
    def test_get_with_descendants(self, mget_mock):
        mget_mock.side_effect = self.mget_side_effect

        topics = TaxonomyTopic.manager.get_with_descendants(['root'])
        expected_calls = [call(['root']), call(['child1', 'child2'])]
        self.assertEqual(mget_mock.mock_calls, expected_calls)
        expected_uuids = sorted(['root', 'child1', 'child2'])
        topic_uuids = sorted([t.data['uuid'] for t in topics])
        self.assertEqual(topic_uuids, expected_uuids)

        topics = TaxonomyTopic.manager.get_with_descendants(['root'], max_depth=2)
        expected_calls = [
            call(['root']),
            call(['child1', 'child2']),
            call(['root']),
            call(['child1', 'child2']),
            call(['grandChild1', 'grandChild2'])
        ]
        self.assertEqual(mget_mock.mock_calls, expected_calls)
        expected_uuids = sorted(['root', 'child1', 'child2', 'grandChild1', 'grandChild2'])
        topic_uuids = sorted([t.data['uuid'] for t in topics])
        self.assertEqual(topic_uuids, expected_uuids)

    @patch('distribution.managers.BaseManager.mget')
    @patch('distribution.managers.BaseManager._search')
    def test_extended_search_with_pagination(self, search_mock, mget_mock):
        """Test correct response when extended_search method is executed."""
        mget_mock.side_effect = self.mget_side_effect
        mock_query = {
            'filter': {
                'bool': {
                    'must': [
                        {
                            'term': {
                                'name': 'example_term'
                            }
                        },
                        {
                            'term': {
                                'topic_type': 'example_type'
                            }
                        },
                    ]
                }
            }
        }

        mock_data = get_sitemap_mock_data()
        mock_result = wrap_search_response(mock_data)
        search_mock.return_value = mock_query, mock_result

        result = TaxonomyTopic.manager.extended_search()
        self.assertIn('items', result)
        self.assertEqual(len(result['items']), 1)
        self.assertIn('paginator', result)
        self.assertIsInstance(result['paginator'], Paginator)

    @patch('distribution.managers.BaseManager.mget')
    @patch('distribution.managers.BaseManager._search')
    def test_extended_search_without_pagination(self, search_mock, mget_mock):
        """Test correct response when extended_search method is executed without pagination."""
        TaxonomyTopic.manager.paginator_class = None
        mget_mock.side_effect = self.mget_side_effect
        mock_query = {
            'filter': {
                'bool': {
                    'must': [
                        {
                            'term': {
                                'name': 'example_term'
                            }
                        },
                        {
                            'term': {
                                'topic_type': 'example_type'
                            }
                        },
                    ]
                }
            }
        }

        mock_data = get_sitemap_mock_data()
        mock_result = wrap_search_response(mock_data)
        search_mock.return_value = mock_query, mock_result

        result = TaxonomyTopic.manager.extended_search()
        self.assertIn('items', result)
        self.assertEqual(len(result['items']), 1)
        self.assertNotIn('paginator', result)

    @patch('elasticsearch.Elasticsearch.search')
    def test_search_by_field_success(self, search_mock):
        """Test correct response when search_by_field method is executed."""
        mock_data = get_sitemap_mock_data()
        search_mock.return_value = wrap_search_response(mock_data)

        call_query = {
            "query": {
                "query_string": {
                    "query": "example_field:\"example_value\"",
                    "default_operator": 'AND'
                }
            }
        }

        result = TaxonomyTopic.manager.search_by_field('example_field', 'example_value')

        search_mock.assert_called_once_with('distribution_taxonomy', '', call_query)
        self.assertEqual(len(result), 1)
        self.assertIsInstance(result[0], SitemapURL)

    @patch('elasticsearch.Elasticsearch.search')
    def test_search_by_field_success_empty_result(self, search_mock):
        """Test raise NotFound exception if Elasticsearch does not find
        any result when the manager execute search_by_field.
        """
        search_mock.return_value = wrap_empty_search_response()

        self.assertRaises(
            NotFound,
            TaxonomyTopic.manager.search_by_field,
            'example_field',
            'example_value'
        )

    @patch('elasticsearch.Elasticsearch.search')
    def test_search_by_field_fail(self, search_mock):
        """Test raise HTTPException if Elasticsearch raise an error when
        the manager execute search_by_field.
        """
        search_mock.side_effect = ElasticsearchRequestError()

        self.assertRaises(
            HTTPException,
            TaxonomyTopic.manager.search_by_field,
            'example_field',
            'example_value'
        )
