# 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 for archives templatetags."""

from typing import override
from unittest import mock

from django.template import TemplateSyntaxError, engines
from django.test import RequestFactory, override_settings
from django.urls import get_urlconf, reverse, set_urlconf

from debusine.db.context import context
from debusine.db.playground import scenarios
from debusine.test.django import TestCase


class DebusineURLTests(TestCase):
    """Tests for debusine_url tag."""

    # The debusine_url template tag currently has dependencies on Django
    # internals, so code coverage is especially important here, to try and
    # check all possible tag behaviours and be more likely to detect breakage
    # with future Django versions

    scenario = scenarios.DefaultContext(set_current=True)

    fqdn = "debusine.example.org"

    @override
    def setUp(self) -> None:
        super().setUp()
        self.enterContext(
            override_settings(
                DEBUSINE_URL_SCHEME="https", DEBUSINE_FQDN=self.fqdn
            )
        )

    def render(self, template_code: str) -> str:
        """Render a template from a string."""
        orig = get_urlconf()
        try:
            set_urlconf("debusine.web.archives.urls")

            request = RequestFactory().get("/")
            template = engines["django"].from_string(
                "{% load archives %}" + template_code
            )
            return template.render({"context": context}, request=request)
        finally:
            set_urlconf(orig)

    def test_homepage(self) -> None:
        self.assertEqual(
            self.render(
                "{% debusine_url 'homepage:homepage' %}",
            ),
            f"https://{self.fqdn}" + reverse("homepage:homepage"),
        )

    def test_workspace(self) -> None:
        self.assertEqual(
            self.render(
                f"{{% debusine_url 'workspaces:detail' "
                f"wname={self.scenario.workspace.name!r} %}}",
            ),
            f"https://{self.fqdn}"
            + reverse(
                "workspaces:detail",
                kwargs={"wname": self.scenario.workspace.name},
            ),
        )

    def test_workspace_positional(self) -> None:
        self.assertEqual(
            self.render(
                f"{{% debusine_url 'workspaces:detail' "
                f"{self.scenario.workspace.name!r} %}}",
            ),
            f"https://{self.fqdn}"
            + reverse(
                "workspaces:detail",
                kwargs={"wname": self.scenario.workspace.name},
            ),
        )

    def test_as(self) -> None:
        self.assertEqual(
            self.render(
                "{% debusine_url 'homepage:homepage' as test %}{{test}}",
            ),
            f"https://{self.fqdn}" + reverse("homepage:homepage"),
        )

    def test_argument_required(self) -> None:
        with self.assertRaisesRegex(
            TemplateSyntaxError,
            "takes at least one argument, a URL pattern name.",
        ):
            self.render(
                "{% debusine_url %}",
            )

    def test_assignment_syntax_check(self) -> None:
        with (
            # The way django.template.base.kwarg_re is currently set, there
            # does not seem to be a string that could be generated by the
            # template tokenizer and would not match the regexp.
            #
            # This may change if in the future kwarg_re gets changed, so here's
            # a mock to keep that code path exercised
            mock.patch(
                "django.template.base.Token.split_contents",
                return_value=["url", "'homepage:homepage'", ""],
            ),
            self.assertRaisesRegex(
                TemplateSyntaxError, "Malformed arguments to url tag"
            ),
        ):
            self.render(
                "{% debusine_url 'homepage:homepage' %}",
            )
