"""Unit test helper methods.

SPDX-FileCopyrightText: © 2020 Brian S. Stephan <bss@incorporeal.org>
SPDX-License-Identifier: AGPL-3.0-or-later
"""
import os

import pytest
from werkzeug.http import dump_cookie

from incorporealcms import create_app
from incorporealcms.pages import (generate_parent_navs, instance_resource_path_to_request_path, render,
                                  request_path_to_breadcrumb_display, request_path_to_instance_resource_path)

HERE = os.path.dirname(os.path.abspath(__file__))


def test_generate_page_navs_index(app):
    """Test that the index page has navs to the root (itself)."""
    with app.app_context():
        assert generate_parent_navs('pages/index.md') == [('example.com', '/')]


def test_generate_page_navs_subdir_index(app):
    """Test that dir pages have navs to the root and themselves."""
    with app.app_context():
        assert generate_parent_navs('pages/subdir/index.md') == [('example.com', '/'), ('subdir', '/subdir/')]


def test_generate_page_navs_subdir_real_page(app):
    """Test that real pages have navs to the root, their parent, and themselves."""
    with app.app_context():
        assert generate_parent_navs('pages/subdir/page.md') == [('example.com', '/'), ('subdir', '/subdir/'),
                                                                ('Page', '/subdir/page')]


def test_generate_page_navs_subdir_with_title_parsing_real_page(app):
    """Test that title metadata is used in the nav text."""
    with app.app_context():
        assert generate_parent_navs('pages/subdir-with-title/page.md') == [
            ('example.com', '/'),
            ('SUB!', '/subdir-with-title/'),
            ('page', '/subdir-with-title/page')
        ]


def test_generate_page_navs_subdir_with_no_index(app):
    """Test that breadcrumbs still generate even if a subdir doesn't have an index.md."""
    with app.app_context():
        assert generate_parent_navs('pages/no-index-dir/page.md') == [
            ('example.com', '/'),
            ('/no-index-dir/', '/no-index-dir/'),
            ('page', '/no-index-dir/page')
        ]


def test_render_with_user_dark_theme(app):
    """Test that a request with the dark theme selected renders the dark theme."""
    cookie = dump_cookie("user-style", 'dark')
    with app.test_request_context(headers={'COOKIE': cookie}):
        assert b'/static/css/dark.css' in render('base.html').data
        assert b'/static/css/light.css' not in render('base.html').data


def test_render_with_user_light_theme(app):
    """Test that a request with the light theme selected renders the light theme."""
    with app.test_request_context():
        assert b'/static/css/light.css' in render('base.html').data
        assert b'/static/css/dark.css' not in render('base.html').data


def test_render_with_no_user_theme(app):
    """Test that a request with no theme set renders the light theme."""
    with app.test_request_context():
        assert b'/static/css/light.css' in render('base.html').data
        assert b'/static/css/dark.css' not in render('base.html').data


def test_render_with_theme_defaults_affects_html(app):
    """Test that the base themes are all that's presented in the HTML."""
    # test we can remove stuff from the default
    with app.test_request_context():
        assert b'?style=light' in render('base.html').data
        assert b'?style=dark' in render('base.html').data
        assert b'?style=plain' in render('base.html').data


def test_render_with_theme_overrides_affects_html(app):
    """Test that the overridden themes are presented in the HTML."""
    # test we can remove stuff from the default
    restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
                              test_config={'PAGE_STYLES': {'light': '/static/css/light.css'}})
    with restyled_app.test_request_context():
        assert b'?style=light' in render('base.html').data
        assert b'?style=dark' not in render('base.html').data
        assert b'?style=plain' not in render('base.html').data

    # test that we can add new stuff too/instead
    restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
                              test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
                                                           'warm': '/static/css/warm.css'},
                                           'DEFAULT_PAGE_STYLE': 'warm'})
    with restyled_app.test_request_context():
        assert b'?style=cool' in render('base.html').data
        assert b'?style=warm' in render('base.html').data


def test_render_with_theme_overrides(app):
    """Test that the loaded themes can be overridden from the default."""
    cookie = dump_cookie("user-style", 'cool')
    restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
                              test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
                                                           'warm': '/static/css/warm.css'}})
    with restyled_app.test_request_context(headers={'COOKIE': cookie}):
        assert b'/static/css/cool.css' in render('base.html').data
        assert b'/static/css/warm.css' not in render('base.html').data


def test_render_with_theme_overrides_not_found_is_default(app):
    """Test that theme overrides work, and if a requested theme doesn't exist, the default is loaded."""
    cookie = dump_cookie("user-style", 'nonexistent')
    restyled_app = create_app(instance_path=os.path.join(HERE, 'instance'),
                              test_config={'PAGE_STYLES': {'cool': '/static/css/cool.css',
                                                           'warm': '/static/css/warm.css'},
                                           'DEFAULT_PAGE_STYLE': 'warm'})
    with restyled_app.test_request_context(headers={'COOKIE': cookie}):
        assert b'/static/css/warm.css' in render('base.html').data
        assert b'/static/css/nonexistent.css' not in render('base.html').data


def test_request_path_to_instance_resource_path(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert request_path_to_instance_resource_path('index') == ('pages/index.md', 'markdown')


def test_request_path_to_instance_resource_path_direct_file(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert request_path_to_instance_resource_path('no-title') == ('pages/no-title.md', 'markdown')


def test_request_path_to_instance_resource_path_in_subdir(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert request_path_to_instance_resource_path('subdir/page') == ('pages/subdir/page.md', 'markdown')


def test_request_path_to_instance_resource_path_subdir_index(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert request_path_to_instance_resource_path('subdir/') == ('pages/subdir/index.md', 'markdown')


def test_request_path_to_instance_resource_path_relatives_walked(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('subdir/more-subdir/../../more-metadata') ==
                ('pages/more-metadata.md', 'markdown'))


def test_request_path_to_instance_resource_path_relatives_walked_indexes_work_too(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert request_path_to_instance_resource_path('subdir/more-subdir/../../') == ('pages/index.md', 'markdown')


def test_request_path_to_instance_resource_path_relatives_walked_into_subdirs_also_fine(app):
    """Test a normal URL request is transformed into the file path."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('subdir/more-subdir/../../subdir/page') ==
                ('pages/subdir/page.md', 'markdown'))


def test_request_path_to_instance_resource_path_permission_error_on_ref_above_pages(app):
    """Test that attempts to get above the base dir ("/../../foo") fail."""
    with app.test_request_context():
        with pytest.raises(PermissionError):
            assert request_path_to_instance_resource_path('../unreachable')


def test_request_path_to_instance_resource_path_isadirectory_on_file_like_req_for_dir(app):
    """Test that a request for e.g. '/foo' when foo is a dir indicate to redirect."""
    with app.test_request_context():
        with pytest.raises(IsADirectoryError):
            assert request_path_to_instance_resource_path('subdir')


def test_request_path_to_instance_resource_path_actual_file(app):
    """Test that a request for e.g. '/foo.png' when foo.png is a real file works."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('bss-square-no-bg.png') ==
                ('pages/bss-square-no-bg.png', 'file'))


def test_request_path_to_instance_resource_path_markdown_symlink(app):
    """Test that a request for e.g. '/foo' when foo.md is a symlink to another .md file redirects."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('symlink-to-no-title') ==
                ('pages/no-title.md', 'symlink'))


def test_request_path_to_instance_resource_path_file_symlink(app):
    """Test that a request for e.g. '/foo' when foo.txt is a symlink to another .txt file redirects."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('symlink-to-foo.txt') ==
                ('pages/foo.txt', 'symlink'))


def test_request_path_to_instance_resource_path_dir_symlink(app):
    """Test that a request for e.g. '/foo' when /foo is a symlink to /bar redirects."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('symlink-to-subdir/') ==
                ('pages/subdir', 'symlink'))


def test_request_path_to_instance_resource_path_subdir_symlink(app):
    """Test that a request for e.g. '/foo/baz' when /foo is a symlink to /bar redirects."""
    with app.test_request_context():
        assert (request_path_to_instance_resource_path('symlink-to-subdir/page-no-title') ==
                ('pages/subdir/page-no-title.md', 'symlink'))


def test_request_path_to_instance_resource_path_nonexistant_file_errors(app):
    """Test that a request for something not on disk errors."""
    with app.test_request_context():
        with pytest.raises(FileNotFoundError):
            assert request_path_to_instance_resource_path('nthanpthpnh')


def test_request_path_to_instance_resource_path_absolute_file_errors(app):
    """Test that a request for something not on disk errors."""
    with app.test_request_context():
        with pytest.raises(PermissionError):
            assert request_path_to_instance_resource_path('/etc/hosts')


def test_instance_resource_path_to_request_path_on_index(app):
    """Test index.md -> /."""
    with app.test_request_context():
        assert instance_resource_path_to_request_path('index.md') == ''


def test_instance_resource_path_to_request_path_on_page(app):
    """Test no-title.md -> no-title."""
    with app.test_request_context():
        assert instance_resource_path_to_request_path('no-title.md') == 'no-title'


def test_instance_resource_path_to_request_path_on_subdir(app):
    """Test subdir/index.md -> subdir/."""
    with app.test_request_context():
        assert instance_resource_path_to_request_path('subdir/index.md') == 'subdir/'


def test_instance_resource_path_to_request_path_on_subdir_and_page(app):
    """Test subdir/page.md -> subdir/page."""
    with app.test_request_context():
        assert instance_resource_path_to_request_path('subdir/page.md') == 'subdir/page'


def test_request_resource_request_root(app):
    """Test that a request can resolve to a resource and back to a request."""
    with app.test_request_context():
        instance_path, _ = request_path_to_instance_resource_path('index')
        instance_resource_path_to_request_path(instance_path) == ''


def test_request_resource_request_page(app):
    """Test that a request can resolve to a resource and back to a request."""
    with app.test_request_context():
        instance_path, _ = request_path_to_instance_resource_path('no-title')
        instance_resource_path_to_request_path(instance_path) == 'no-title'


def test_request_path_to_breadcrumb_display_patterns():
    """Test various conversions from request path to leaf nodes for display in the breadcrumbs."""
    assert request_path_to_breadcrumb_display('/foo') == 'foo'
    assert request_path_to_breadcrumb_display('/foo/') == 'foo'
    assert request_path_to_breadcrumb_display('/foo/bar') == 'bar'
    assert request_path_to_breadcrumb_display('/foo/bar/') == 'bar'
    assert request_path_to_breadcrumb_display('/') == ''