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

# This file is part of PGWUI_Common.
#
# 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 pyramid.config
import pyramid.testing
from pyramid.threadlocal import get_current_request

import pgwui_common.urls as urls
import pgwui_common.view as view
import pgwui_common.pgwui_common as pgwui_common

from pgwui_develop import testing

# Activiate the PGWUI pytest plugin
pytest_plugins = ("pgwui",)


# Helper functions and constants

FOO_URL = 'foo://bar/'

mock_find_pgwui_components = testing.make_mock_fixture(
    urls, 'find_pgwui_components')

mock_method_route_path = testing.instance_method_mock_fixture('route_path')
mock_route_url = testing.instance_method_mock_fixture('route_url')
mock_include = testing.instance_method_mock_fixture('include')
mock_add_static_view = testing.instance_method_mock_fixture('add_static_view')
mock_add_route = testing.instance_method_mock_fixture('add_route')
mock_add_view = testing.instance_method_mock_fixture('add_view')
mock_static_path = testing.instance_method_mock_fixture('static_path')


def mock_view(request):
    if (hasattr(request, 'registry')
            and 'pgwui' in request.registry.settings):
        return request.registry.settings
    return {'pgwui': {'foo': FOO_URL}}


def check_base_view_results(request, pgwui):
    assert pgwui['foo'] == FOO_URL


# Unit tests

# configure_page()

@pytest.mark.unittest
def test_configure_page_no_page():
    '''When there's no setting for the page, nothing is done
    '''
    pgwui_common.configure_page(None, {}, 'test_page')


@pytest.mark.unittest
def test_configure_page_not_file():
    '''When the type of the page is not "file",nothing is done
    '''
    pgwui_common.configure_page(
        None, {'test_page': {'type': 'other'}}, 'test_page')


@pytest.mark.unittest
def test_configure_page_file(
        pyramid_request_config, mock_add_route, mock_add_view):
    '''When the type of the page is "file", a route and view are added
    '''
    mocked_add_route = mock_add_route(pyramid_request_config)
    mocked_add_view = mock_add_view(pyramid_request_config)
    pgwui_common.configure_page(
        pyramid_request_config,
        {'test_page': {'type': 'file', 'url_path': 'somepath'}},
        'test_page')

    mocked_add_route.assert_called_once()
    mocked_add_view.assert_called_once()


mock_configure_page = testing.make_mock_fixture(
    pgwui_common, 'configure_page')


# configure_pages()

@pytest.mark.unittest
def test_configure_pages(pyramid_request_config, mock_configure_page):
    '''Calls configure_page() with all the pages
    '''
    pgwui = 'pgwui'
    pyramid_request_config.get_settings()['pgwui'] = pgwui
    pgwui_common.configure_pages(pyramid_request_config)

    assert (set([call[0] for call in mock_configure_page.call_args_list])
            == set([(pyramid_request_config, pgwui, 'home_page'),
                    (pyramid_request_config, pgwui, 'menu_page')]))


mock_configure_pages = testing.make_mock_fixture(
    pgwui_common, 'configure_pages')


# includeme()

@pytest.mark.unittest
def test_includeme_configurecalled(
        mock_add_static_view, mock_include, mock_configure_pages):
    '''Pyramid Configure() methods are called'''
    with pyramid.testing.testConfig() as config:
        mocked_include = mock_include(config)
        mocked_add_static_view = mock_add_static_view(config)
        pgwui_common.includeme(config)
        assert mocked_include.call_count == 2
        mocked_add_static_view.assert_called_once()
    mock_configure_pages.assert_called_once()


# Integration tests

# auth_base_view()

@pytest.mark.integrationtest
def test_auth_base_view_integration(
        pyramid_request_config, mock_find_pgwui_components):
    '''There are urls for every component
    '''
    test_urls = {
        'pgwui_menu': '/menu',
        'pgwui_logout': '/logout',
        'pgwui_foo': '/foo'}

    test_pgwui = {'home_page': {'type': 'URL', 'source': '/'},
                  'urls': test_urls.copy()}

    mock_find_pgwui_components.return_value = list(test_urls)

    pyramid_request_config.add_settings(pgwui=test_pgwui)
    pgwui_common.includeme(pyramid_request_config)
    for name, url in test_urls.items():
        pyramid_request_config.add_route(name, url)

    wrapper = view.auth_base_view(mock_view)
    request = get_current_request()
    result = wrapper(request)

    # The 'home_page' route is not added because it is (normally) added
    # to the pgwui settings by pgwui_server.py.
    assert result['pgwui']['urls'] == test_urls


# includeme()

@pytest.mark.integrationtest
def test_includeme():
    pgwui = {'home_page': {'type': 'file',
                           'url_path': '/'}}

    config = pyramid.config.Configurator()
    config.registry.settings['pgwui'] = pgwui
    pgwui_common.includeme(config)
