# (c) cavaliba.com - tests / flash messages rendered as a bottom-right fixed stack

from django.core.cache import cache as cache_django
from django.test import TestCase, override_settings
from django.urls import reverse

import app_home.cache as cache
from tests import helper


class TestFlashMessageStack(TestCase):
    def setUp(self):
        cache.clear()
        cache_django.clear()

    def _page_with_a_message(self):
        # a refused factory reset adds an ERROR message, then redirects to the
        # admintools page that renders it
        helper.add_user_with_perm(login="unittest", perms=["p_admintools"])
        return self.client.post(reverse("app_home:admintools_factory_reset"), {}, follow=True)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_message_rendered_inside_the_flash_stack(self):
        response = self._page_with_a_message()
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "An admin account is required.", status_code=200)
        self.assertContains(response, 'class="cv-flash-stack"', status_code=200)
        self.assertContains(response, "cv-flash-item", status_code=200)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_stack_is_outside_the_page_wrapper(self):
        # out of the document flow: it must render after the wrapper closes, so an
        # auto-dismissed alert cannot shift the page content
        response = self._page_with_a_message()
        content = response.content.decode()
        wrapper_end = content.find("<!-- WRAPPER -->")
        stack = content.find('class="cv-flash-stack"')
        self.assertGreater(wrapper_end, -1)
        self.assertGreater(stack, wrapper_end)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_no_stack_without_message(self):
        helper.add_admin_user(login="unittest")
        response = self.client.get(reverse("app_home:admintools"), follow=True)
        self.assertEqual(response.status_code, 200)
        # the class name also appears in a JS comment in base.html, so assert on
        # the element itself
        self.assertNotContains(response, '<div class="cv-flash-stack">', status_code=200)
        self.assertNotContains(response, "cv-flash-item", status_code=200)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_several_messages_stack_in_one_container(self):
        # each refused POST queues one ERROR message ; not following the redirect
        # leaves them in the session, so the next rendered page shows all three
        helper.add_user_with_perm(login="unittest", perms=["p_admintools"])
        url = reverse("app_home:admintools_factory_reset")
        for _i in range(3):
            self.client.post(url, {}, follow=False)

        response = self.client.get(reverse("app_home:admintools"), follow=True)
        content = response.content.decode()

        self.assertEqual(content.count('<div class="cv-flash-stack">'), 1)
        self.assertEqual(content.count("cv-flash-item"), 3)
        self.assertEqual(content.count("An admin account is required."), 3)

    @override_settings(CAVALIBA_AUTH_MODE="unittest")
    def test_alert_stays_dismissible_for_the_auto_close_script(self):
        # the 3s timer in base.html targets .alert.alert-dismissible
        response = self._page_with_a_message()
        self.assertContains(response, "alert-dismissible", status_code=200)
        self.assertContains(response, 'data-bs-dismiss="alert"', status_code=200)
