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

# Copyright (C) 2015 Avencall
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>

from unittest import TestCase
from flask import Flask

from hamcrest import assert_that, equal_to
from mock import patch, Mock, sentinel

from xivo_dird.plugins import phone_view

class TestPhoneView(TestCase):
    
    def setUp(self):
        self.app = Flask(__name__)
        self.ctx = self.app.test_request_context()
        self.ctx.push()

    def tearDown(self):
        self.ctx.pop()

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_input_url_when_is_menu(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/{}/profile/vendor'
        expected_result = url.format('input')
        MockedRequest.base_url = url.format('menu')
        result = phone_view._build_next_url('menu')

        assert_that(result, equal_to(expected_result))

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_input_url_when_is_menu_with_profile_menu(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/{}/menu/vendor'
        expected_result = url.format('input')
        MockedRequest.base_url = url.format('menu')
        result = phone_view._build_next_url('menu')

        assert_that(result, equal_to(expected_result))

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_lookup_url_when_is_input(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/{}/profile/vendor'
        expected_result = url.format('lookup')
        MockedRequest.base_url = url.format('input')
        result = phone_view._build_next_url('input')

        assert_that(result, equal_to(expected_result))

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_lookup_url_when_is_input_with_profile_input(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/{}/input/vendor'
        expected_result = url.format('lookup')
        MockedRequest.base_url = url.format('input')
        result = phone_view._build_next_url('input')

        assert_that(result, equal_to(expected_result))

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_same_url_when_is_lookup(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/lookup/profile/vendor'
        expected_result = url
        MockedRequest.base_url = url
        result = phone_view._build_next_url('lookup')

        assert_that(result, equal_to(expected_result))

    @patch('xivo_dird.plugins.phone_view.request')
    def test_that_build_next_url_return_same_url_when_is_lookup_by_label(self, MockedRequest):
        url = 'http://127.0.0.1:9489/0.1/directories/lookup_by_label/uuid/vendor'
        expected_result = url
        MockedRequest.base_url = url
        result = phone_view._build_next_url('lookup_by_label')

        assert_that(result, equal_to(expected_result))


class TestPhoneLookupByLabel(TestCase):

    def setUp(self):
        self.app = Flask(__name__)
        self.ctx = self.app.test_request_context()
        self.ctx.push()

    def tearDown(self):
        self.ctx.pop()

    def test_labels_for_user_returns_assigned_labels_from_path_uuid(self):
        label_dao = Mock()
        label_dao.label_ids_for_user.return_value = [1, 2, 3]
        resource = phone_view.PhoneLookupByLabel(sentinel.template, sentinel.content_type, Mock(), label_dao)

        result = resource._labels_for_user(sentinel.uuid)

        assert_that(result, equal_to([1, 2, 3]))
        label_dao.label_ids_for_user.assert_called_once_with(sentinel.uuid)

    def test_labels_for_user_returns_empty_when_no_dao(self):
        resource = phone_view.PhoneLookupByLabel(sentinel.template, sentinel.content_type, Mock(), None)

        result = resource._labels_for_user(sentinel.uuid)

        assert_that(result, equal_to([]))

    def test_labels_for_user_propagates_dao_error_instead_of_returning_empty(self):
        label_dao = Mock()
        label_dao.label_ids_for_user.side_effect = Exception('db is down')
        resource = phone_view.PhoneLookupByLabel(sentinel.template, sentinel.content_type, Mock(), label_dao)

        self.assertRaises(Exception, resource._labels_for_user, sentinel.uuid)

    @patch('xivo_dird.plugins.phone_view.request')
    def test_get_fails_closed_with_503_when_labels_cannot_be_read(self, MockedRequest):
        MockedRequest.headers = {'X-Auth-Token': 'a-token'}
        label_dao = Mock()
        label_dao.label_ids_for_user.side_effect = Exception('db is down')
        phone_lookup_service = Mock()
        resource = phone_view.PhoneLookupByLabel(sentinel.template, sentinel.content_type,
                                                 phone_lookup_service, label_dao)
        resource.parser = Mock()
        resource.parser.parse_args.return_value = {'term': 'alice', 'offset': 0, 'limit': None}

        body, status_code = resource.get('some-user-uuid')

        assert_that(status_code, equal_to(503))
        # the lookup must not run at all: no fallback to default_sources
        assert_that(phone_lookup_service.lookup_by_labels.called, equal_to(False))
