# Copyright (C) 2020, 2021 The Meme Factory, Inc.  http://www.karlpinc.com/

# This file is part of PGWUI_Menu.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero 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
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
#

# Karl O. Pinc <kop@karlpinc.com>

import pytest

import copy
import pyramid.testing

from pgwui_common import plugin, includeme
from pgwui_menu.views import menu

from pgwui_develop import testing

# Activiate our pytest plugin
pytest_plugins = ("pgwui",)

mock_find_pgwui_components = testing.make_mock_fixture(
    plugin, 'find_pgwui_components')
mock_route_url = testing.instance_method_mock_fixture('route_url')


# Unit tests

# build_menu()

@pytest.mark.unittest
def test_build_menu_no_component():
    '''When the plugin has no setting the menu is not modified
    '''
    menu_items = []
    menu.build_menu(None, {}, menu_items, 'pgwui_dummy')

    assert menu_items == []


@pytest.mark.unittest
def test_build_menu_component_with_route(mock_route_url):
    '''When the plugin has a setting and a route the route is
    returned with the label
    '''
    test_route = '/test/route'
    test_plugin = 'pgwui_plugin'
    plugin_settings = {'key1': 'val1', 'key2': 'val2'}
    test_settings = {test_plugin: plugin_settings}

    request = pyramid.testing.DummyRequest()
    mocked_route_url = mock_route_url(request)
    mocked_route_url.return_value = test_route
    request.registry.settings = test_settings

    menu_items = []
    menu.build_menu(request, test_settings, menu_items, test_plugin)

    assert menu_items == [(test_plugin, test_route, plugin_settings)]


@pytest.mark.unittest
def test_build_menu_component_no_route(mock_route_url):
    '''When the plugin has a setting and no route, the menu is not modified
    '''
    test_plugin = 'pgwui_plugin'
    plugin_settings = {'key1': 'val1', 'key2': 'val2'}
    test_settings = {test_plugin: plugin_settings}

    request = pyramid.testing.DummyRequest()
    mocked_route_url = mock_route_url(request)
    mocked_route_url.side_effect = KeyError
    request.registry.settings = test_settings

    menu_items = []
    menu.build_menu(request, test_settings, menu_items, test_plugin)

    assert menu_items == []


mock_build_menu = testing.make_mock_fixture(
    menu, 'build_menu')


# build_menu_items()

@pytest.mark.unittest
def test_build_menu_items_component_no_plugin_conf(mock_build_menu):
    '''Components given in the pgwui_menu.order setting are added
    in order, other components are added alphabetically, the pgwui_menu
    component is not added
    '''
    components = ['plugin5', 'plugin4', 'pgwui_menu', 'plugin2', 'plugin1']
    orig_components = copy.deepcopy(components)
    test_settings = {'pgwui':
                     {'pgwui_menu':
                      {'order': ['plugin5', 'plugin2']}}}

    request = pyramid.testing.DummyRequest()
    request.registry.settings = test_settings

    menu.build_menu_items(request, components)

    call_args = mock_build_menu.call_args_list
    # Check the order of the ordered components
    assert call_args[0][0][3] == 'plugin5'
    assert call_args[1][0][3] == 'plugin2'
    # The pgwui_menu is ignored
    assert len(call_args) == len(orig_components) - 1
    # Check that order of the remaining components is alphabetical
    assert call_args[2][0][3] == 'plugin1'
    assert call_args[3][0][3] == 'plugin4'


@pytest.mark.unittest
def test_build_menu_items_no_order(mock_build_menu):
    '''When there is no order setting components are added alphabetically
    '''
    components = ['plugin5', 'plugin4', 'pgwui_menu', 'plugin2', 'plugin1']
    orig_components = copy.deepcopy(components)
    test_settings = {'pgwui':
                     {'pgwui_menu': {}}}

    request = pyramid.testing.DummyRequest()
    request.registry.settings = test_settings

    menu.build_menu_items(request, components)

    call_args = mock_build_menu.call_args_list
    # The pgwui_menu is ignored
    assert len(call_args) == len(orig_components) - 1
    # Check the order of the ordered components
    assert call_args[0][0][3] == 'plugin1'
    assert call_args[1][0][3] == 'plugin2'
    assert call_args[2][0][3] == 'plugin4'
    assert call_args[3][0][3] == 'plugin5'


mock_build_menu_items = testing.make_mock_fixture(
    menu, 'build_menu_items')


# menu_view()

@pytest.mark.unittest
def test_menu_view(pyramid_config,
                   mock_find_pgwui_components,
                   mock_build_menu_items):
    '''The menu items are in the request
    '''
    test_menu_items = [('a', 'r1', 'l1'), ('b', 'r2', 'l2')]
    test_pgwui_menu_settings = 'some value'
    mock_build_menu_items.return_value = test_menu_items

    request = pyramid.testing.DummyRequest()
    request.registry.settings['pgwui'] = {'pgwui_menu':
                                          test_pgwui_menu_settings,
                                          'home_page': {'type': 'URL',
                                                        'source': '/'},
                                          'urls': {}}
    includeme(pyramid_config)
    result = menu.menu_view(request)

    assert result['menu_items'] == test_menu_items
    assert result['pgwui_menu'] == test_pgwui_menu_settings


# Integration tests
