# Copyright © The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Tests the scopes UI helper."""

from django.core.exceptions import ImproperlyConfigured
from django.test import RequestFactory
from django.urls import reverse

from debusine.db.context import context
from debusine.db.permissioncontext import PermissionContext
from debusine.db.playground import scenarios
from debusine.test.django import TestCase
from debusine.web.icons import Icons
from debusine.web.views.places import ContainerPlace
from debusine.web.views.ui.scopes import ScopePlace, ScopeUI


class ScopeUITests(TestCase):
    """Test the :py:class:`ScopeUI` class."""

    scenario = scenarios.DefaultContext(set_current=True)

    def ui(self) -> ScopeUI:
        """Instantiate the UI helper to test."""
        assert context.user
        factory = RequestFactory()
        request = factory.get("/")
        request.user = context.user
        return self.scenario.scope.ui(request)

    def test_place(self) -> None:
        place = self.ui().place
        self.assertEqual(place.title, self.scenario.scope.name)
        self.assertEqual(place.description, "debusine scope")
        self.assertEqual(place.url, reverse("scopes:detail"))
        self.assertEqual(place.icon, Icons.SCOPE)
        self.assertIsNone(place.parent)
        self.assertEqual(place.breadcrumb, self.scenario.scope.name)

    def test_place_with_icon(self) -> None:
        self.scenario.scope.icon = "icon.png"
        self.scenario.scope.save()
        place = self.ui().place
        self.assertIsInstance(place, ScopePlace)
        self.assertEqual(place.title, self.scenario.scope.name)
        self.assertEqual(place.description, "debusine scope")
        self.assertEqual(place.url, reverse("scopes:detail"))
        self.assertEqual(place.icon, "icon.png")
        self.assertIsNone(place.parent)
        self.assertEqual(place.breadcrumb, self.scenario.scope.name)

    def test_place_group_list(self) -> None:
        place = self.ui().place_group_list
        self.assertIsInstance(place, ContainerPlace)
        self.assertEqual(
            place.title, "Group list for playground in scope debusine"
        )
        self.assertEqual(
            place.description,
            f"Groups in scope debusine accessible by {self.scenario.user}",
        )
        self.assertEqual(
            place.url, reverse("user:groups", kwargs={"username": "playground"})
        )
        self.assertIsNone(place.icon)
        self.assertEqual(place.breadcrumb, "groups")
        assert place.parent is not None
        self.assertEqual(place.parent.url, reverse("scopes:detail"))

    @context.local()
    def test_place_group_list_unauthenticated(self) -> None:
        context.reset()
        context.set_permission_context_scoped(
            self.scenario.scope, PermissionContext.for_ui_anonymous()
        )
        with self.assertRaisesRegex(
            ImproperlyConfigured,
            "ScopeUI.place_group_list invoked by an anonymous user",
        ):
            self.ui().place_group_list


class ScopePlaceTests(TestCase):
    """Test the :py:class:`ScopePlace` class."""

    def test_as_nav(self) -> None:
        place = ScopePlace(
            title="test title", url="/test-url", breadcrumb="test"
        )
        tree = self.assertHTMLValid(place.as_nav())
        a = self.assertHasElement(tree, "//a")
        self.assertTextContentEqual(a, "test title")
        self.assertEqual(a.get("href"), "/test-url")

    def test_as_nav_icon(self) -> None:
        place = ScopePlace(
            title="test title",
            url="/test-url",
            icon="icon.png",
            description="description",
            breadcrumb="test",
        )
        tree = self.assertHTMLValid(place.as_nav())
        a = self.assertHasElement(tree, "//a")
        self.assertTextContentEqual(a, "test title")
        self.assertEqual(a.get("href"), "/test-url")

        img = self.assertHasElement(a, "img")
        self.assertEqual(img.get("src"), "/static/icon.png")

    def test_as_page_title(self) -> None:
        place = ScopePlace(title="test title", url="url", breadcrumb="test")
        tree = self.assertHTMLValid(place.as_page_title())
        title = self.assertHasElement(tree, "//h1")
        self.assertTextContentEqual(title, "test title")

    def test_as_page_title_icon(self) -> None:
        place = ScopePlace(
            title="test title", url="url", icon="icon.png", breadcrumb="test"
        )
        tree = self.assertHTMLValid(place.as_page_title())
        h1 = self.assertHasElement(tree, "//h1")
        self.assertTextContentEqual(h1, "test title")

    def test_as_page_title_icon_title(self) -> None:
        place = ScopePlace(
            title="test title",
            url="url",
            icon="icon.png",
            description="distinction",
            breadcrumb="test",
        )
        tree = self.assertHTMLValid(place.as_page_title())
        h1 = self.assertHasElement(tree, "//h1")
        self.assertTextContentEqual(h1, "test title")
