from django.contrib.admin.tests import AdminSeleniumTestCase
from django.contrib.auth.models import User
from django.test import override_settings
from django.urls import reverse

from .models import Podcast


@override_settings(ROOT_URLCONF="admin_views.urls")
class SeleniumTests(AdminSeleniumTestCase):
    available_apps = ["admin_views"] + AdminSeleniumTestCase.available_apps

    def setUp(self):
        self.superuser = User.objects.create_superuser(
            username="super",
            password="secret",
            email="super@example.com",
        )

    def test_use_skip_link_to_content(self):
        from selenium.webdriver.common.action_chains import ActionChains
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys

        self.admin_login(
            username="super",
            password="secret",
            login_url=reverse("admin:index"),
        )

        # `Skip link` is not present.
        skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
        self.assertFalse(skip_link.is_displayed())

        # 1st TAB is pressed, `skip link` is shown.
        body = self.selenium.find_element(By.TAG_NAME, "body")
        body.send_keys(Keys.TAB)
        self.assertTrue(skip_link.is_displayed())

        # Press RETURN to skip the navbar links (view site / documentation /
        # change password / log out) and focus first model in the admin_views
        # list.
        skip_link.send_keys(Keys.RETURN)
        self.assertFalse(skip_link.is_displayed())  # `skip link` disappear.
        keys = [Keys.TAB, Keys.TAB]  # The 1st TAB is the section title.
        if self.browser == "firefox":
            # For some reason Firefox doesn't focus the section title
            # ('ADMIN_VIEWS').
            keys.remove(Keys.TAB)
        body.send_keys(keys)
        actors_a_tag = self.selenium.find_element(By.LINK_TEXT, "Actors")
        self.assertEqual(self.selenium.switch_to.active_element, actors_a_tag)

        # Go to Actors changelist, skip sidebar and focus "Add actor +".
        with self.wait_page_loaded():
            actors_a_tag.send_keys(Keys.RETURN)
        body = self.selenium.find_element(By.TAG_NAME, "body")
        body.send_keys(Keys.TAB)
        skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
        self.assertTrue(skip_link.is_displayed())
        ActionChains(self.selenium).send_keys(Keys.RETURN, Keys.TAB).perform()
        actors_add_url = reverse("admin:admin_views_actor_add")
        actors_a_tag = self.selenium.find_element(
            By.CSS_SELECTOR, f"#content [href='{actors_add_url}']"
        )
        self.assertEqual(self.selenium.switch_to.active_element, actors_a_tag)

        # Go to the Actor form and the first input will be focused
        # automatically.
        with self.wait_page_loaded():
            actors_a_tag.send_keys(Keys.RETURN)
        first_input = self.selenium.find_element(By.ID, "id_name")
        self.assertEqual(self.selenium.switch_to.active_element, first_input)

    def test_dont_use_skip_link_to_content(self):
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys

        self.admin_login(
            username="super",
            password="secret",
            login_url=reverse("admin:index"),
        )

        # `Skip link` is not present.
        skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
        self.assertFalse(skip_link.is_displayed())

        # 1st TAB is pressed, `skip link` is shown.
        body = self.selenium.find_element(By.TAG_NAME, "body")
        body.send_keys(Keys.TAB)
        self.assertTrue(skip_link.is_displayed())

        # The 2nd TAB will focus the page title.
        body.send_keys(Keys.TAB)
        django_administration_title = self.selenium.find_element(
            By.LINK_TEXT, "Django administration"
        )
        self.assertFalse(skip_link.is_displayed())  # `skip link` disappear.
        self.assertEqual(
            self.selenium.switch_to.active_element, django_administration_title
        )

    def test_skip_link_with_RTL_language_doesnt_create_horizontal_scrolling(self):
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys

        with override_settings(LANGUAGE_CODE="ar"):
            self.admin_login(
                username="super",
                password="secret",
                login_url=reverse("admin:index"),
            )

            skip_link = self.selenium.find_element(
                By.CLASS_NAME, "skip-to-content-link"
            )
            body = self.selenium.find_element(By.TAG_NAME, "body")
            body.send_keys(Keys.TAB)
            self.assertTrue(skip_link.is_displayed())

            is_vertical_scrolleable = self.selenium.execute_script(
                "return arguments[0].scrollHeight > arguments[0].offsetHeight;", body
            )
            is_horizontal_scrolleable = self.selenium.execute_script(
                "return arguments[0].scrollWeight > arguments[0].offsetWeight;", body
            )
            self.assertTrue(is_vertical_scrolleable)
            self.assertFalse(is_horizontal_scrolleable)

    def test_skip_link_keyboard_navigation_in_changelist(self):
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys

        Podcast.objects.create(name="apple", release_date="2000-09-19")
        self.admin_login(
            username="super", password="secret", login_url=reverse("admin:index")
        )
        self.selenium.get(
            self.live_server_url + reverse("admin:admin_views_podcast_changelist")
        )
        selectors = [
            "ul.object-tools",  # object_tools.
            "search#changelist-filter",  # list_filter.
            "form#changelist-search",  # search_fields.
            "nav.toplinks",  # date_hierarchy.
            "form#changelist-form div.actions",  # action.
            "table#result_list",  # table.
            "div.changelist-footer",  # footer.
        ]
        content = self.selenium.find_element(By.ID, "content-start")
        content.send_keys(Keys.TAB)

        for selector in selectors:
            with self.subTest(selector=selector):
                # Currently focused element.
                focused_element = self.selenium.switch_to.active_element
                expected_element = self.selenium.find_element(By.CSS_SELECTOR, selector)
                element_points = self.selenium.find_elements(
                    By.CSS_SELECTOR,
                    f"{selector} a, {selector} input, {selector} button",
                )
                self.assertIn(
                    focused_element.get_attribute("outerHTML"),
                    expected_element.get_attribute("innerHTML"),
                )
                # Move to the next container element via TAB.
                for point in element_points[::-1]:
                    if point.is_displayed():
                        point.send_keys(Keys.TAB)
                        break
