# -*- coding: utf-8 -*-
#
# Copyright (C) 2026 XiVO Solutions
#
# 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 xml.dom.minidom import parseString as parse_xml

from hamcrest import assert_that
from hamcrest import contains_inanyorder
from hamcrest import equal_to

from .base_dird_integration_test import BaseDirdIntegrationTest
from .base_dird_integration_test import VALID_TOKEN
from .base_dird_integration_test import VALID_UUID


class TestPhoneLookupByLabel(BaseDirdIntegrationTest):
    asset = 'lookup_by_labels'

    # This asset configures no `db_uri` at all, so the views build no label DAO
    # and the resolved label set is empty: the search service then falls back to
    # `default_sources`.
    #
    # Label -> sources resolution itself is covered by TestLookupByLabels; what
    # is asserted here is the phone entry point: profile-less route, path uuid,
    # phone display, and authorization.
    #
    # config (etc/xivo-dird/config.yml):
    #   default_sources: [dir_default]                    -> Default Smith, 1000
    #   profile_to_display_phone: lookup_by_labels -> lookup_by_labels_phone

    def test_that_the_phone_route_is_profile_less_and_answers(self):
        response = self.get_lookup_by_label_cisco_result(VALID_UUID,
                                                         term='smith',
                                                         token=VALID_TOKEN)

        assert_that(response.status_code, equal_to(200))

    def test_that_an_unresolvable_label_set_falls_back_to_default_sources(self):
        xml_content = self.get_lookup_by_label_cisco(VALID_UUID, term='smith', token=VALID_TOKEN)

        assert_that(_names(xml_content), contains_inanyorder('Default'))

    def test_that_results_are_rendered_with_the_phone_display(self):
        xml_content = self.get_lookup_by_label_cisco(VALID_UUID, term='smith', token=VALID_TOKEN)

        # the phone display maps name -> firstname and number -> number
        assert_that(_entries(xml_content), contains_inanyorder(('Default', '1000')))

    def test_that_no_result_is_returned_when_the_term_does_not_match(self):
        xml_content = self.get_lookup_by_label_cisco(VALID_UUID, term='nobody', token=VALID_TOKEN)

        # the phone templates render a placeholder entry when there is no result
        assert_that(_entries(xml_content), equal_to([('No entries', '')]))

    def test_that_term_is_required(self):
        response = self.get_lookup_by_label_cisco_result(VALID_UUID, token=VALID_TOKEN)

        assert_that(response.status_code, equal_to(400))

    def test_that_an_unknown_token_is_rejected(self):
        response = self.get_lookup_by_label_cisco_result(VALID_UUID,
                                                         term='smith',
                                                         token='unknown-token')

        assert_that(response.status_code, equal_to(401))

    def test_that_no_token_is_rejected(self):
        response = self.get_lookup_by_label_cisco_result(VALID_UUID, term='smith')

        assert_that(response.status_code, equal_to(401))


def _entries(xml_string):
    document = parse_xml(xml_string)
    results = []
    for directory_entry in document.getElementsByTagName('DirectoryEntry'):
        name = _text(directory_entry.getElementsByTagName('Name')[0])
        number = _text(directory_entry.getElementsByTagName('Telephone')[0])
        results.append((name, number))
    return results


def _names(xml_string):
    return [name for name, _ in _entries(xml_string)]


def _text(element):
    return ''.join(node.data for node in element.childNodes
                   if node.nodeType == node.TEXT_NODE)
