"""
Accessibility Backend Tests
Tests for HTML structure and semantic markup accessibility
"""

import pytest
import requests
from bs4 import BeautifulSoup
import re
from urllib.parse import urljoin


class TestHTMLAccessibility:
    """Test HTML structure for accessibility compliance"""

    @pytest.fixture
    def research_page_html(self, base_url):
        """Fetch the research page HTML"""
        response = requests.get(urljoin(base_url, "/research/"))
        response.raise_for_status()
        return BeautifulSoup(response.content, "html.parser")

    def test_form_has_proper_labels(self, research_page_html):
        """Test that all form inputs have proper labels"""
        soup = research_page_html

        # Find all input elements that should have labels
        inputs = soup.find_all(["input", "textarea", "select"])

        for input_element in inputs:
            input_id = input_element.get("id")
            input_type = input_element.get("type", "text")

            # Skip hidden inputs and buttons
            if input_type in ["hidden", "submit", "button"]:
                continue

            # Check for associated label
            if input_id:
                label = soup.find("label", {"for": input_id})
                assert label is not None, (
                    f"Input with id '{input_id}' missing associated label"
                )

    def test_radio_button_structure(self, research_page_html):
        """Test that radio buttons are properly structured"""
        soup = research_page_html

        # Find radio button group
        radio_inputs = soup.find_all("input", {"name": "research_mode"})
        assert len(radio_inputs) == 2, (
            "Should have exactly 2 research mode radio buttons"
        )

        # Check that radio buttons have proper IDs and labels
        expected_modes = ["quick", "detailed"]
        for mode in expected_modes:
            radio = soup.find("input", {"id": f"mode-{mode}"})
            assert radio is not None, f"Missing radio button for {mode} mode"
            assert radio.get("type") == "radio", (
                f"Input for {mode} mode should be type='radio'"
            )
            assert radio.get("name") == "research_mode", (
                "Radio button should have name='research_mode'"
            )

            # Check associated label
            label = soup.find("label", {"for": f"mode-{mode}"})
            assert label is not None, (
                f"Missing label for {mode} mode radio button"
            )
            assert "mode-option" in label.get("class", []), (
                "Label should have mode-option class"
            )

    def test_fieldset_and_legend(self, research_page_html):
        """Test that radio button group has proper fieldset and legend"""
        soup = research_page_html

        fieldset = soup.find("fieldset")
        assert fieldset is not None, (
            "Radio button group should be wrapped in fieldset"
        )

        legend = fieldset.find("legend")
        assert legend is not None, "Fieldset should have a legend"
        assert "Research Mode" in legend.get_text(), (
            "Legend should describe the radio button group"
        )

    def test_aria_attributes(self, research_page_html):
        """Test that ARIA attributes are properly set"""
        soup = research_page_html

        # Check radiogroup role
        radiogroup = soup.find(attrs={"role": "radiogroup"})
        assert radiogroup is not None, (
            "Should have element with role='radiogroup'"
        )

        # Check radio labels have proper ARIA attributes
        radio_labels = soup.find_all("label", class_="mode-option")
        assert len(radio_labels) >= 2, "Should have at least 2 radio labels"

        for label in radio_labels:
            assert label.get("role") == "radio", (
                "Label should have role='radio'"
            )
            assert "aria-checked" in label.attrs, (
                "Label should have aria-checked attribute"
            )
            assert "tabindex" in label.attrs, (
                "Label should have tabindex attribute"
            )

        # Check that one radio is initially checked
        checked_labels = [
            label
            for label in radio_labels
            if label.get("aria-checked") == "true"
        ]
        assert len(checked_labels) == 1, (
            "Exactly one radio should be initially checked"
        )

    def test_screen_reader_only_class(self, research_page_html):
        """Test that radio inputs have screen reader only class"""
        soup = research_page_html

        radio_inputs = soup.find_all("input", {"name": "research_mode"})
        for radio in radio_inputs:
            classes = radio.get("class", [])
            assert "sr-only" in classes, (
                "Radio inputs should have sr-only class"
            )

    def test_keyboard_hints_present(self, research_page_html):
        """Test that keyboard hint text is present"""
        soup = research_page_html

        hint_container = soup.find(class_="search-hints")
        assert hint_container is not None, "Should have search hints container"

        hint_texts = hint_container.find_all(class_="hint-text")
        assert len(hint_texts) >= 2, "Should have at least 2 hint text elements"

        # Get all hint text content
        all_hints = " ".join([hint.get_text() for hint in hint_texts])
        assert "Enter to search" in all_hints, "Should mention Enter key"
        assert "Shift+Enter for new line" in all_hints, (
            "Should mention Shift+Enter for new line"
        )

    def test_icons_have_aria_hidden(self, research_page_html):
        """Test that decorative icons have aria-hidden attribute"""
        soup = research_page_html

        # Find icons in mode options
        mode_icons = soup.find_all(class_="mode-icon")
        for icon_container in mode_icons:
            icon = icon_container.find("i")
            if icon:
                assert icon.get("aria-hidden") == "true", (
                    "Decorative icons should have aria-hidden='true'"
                )

    def test_form_structure(self, research_page_html):
        """Test overall form structure and accessibility"""
        soup = research_page_html

        # Find the main form
        form = soup.find("form", {"id": "research-form"})
        assert form is not None, "Should have main research form"

        # Check that form has proper method (should be handled by JS)
        # Form should not have action attribute as it's handled by JavaScript
        assert form.get("action") is None, (
            "Form should not have action attribute (handled by JS)"
        )

    def test_heading_structure(self, research_page_html):
        """Test that headings follow proper hierarchy"""
        soup = research_page_html

        # Find all headings
        headings = soup.find_all(re.compile(r"^h[1-6]$"))

        if headings:
            # Check that we start with h1 or h2 (allowing for page structure)
            first_heading_level = int(headings[0].name[1])
            assert first_heading_level <= 2, "First heading should be h1 or h2"

            # Check for logical progression (no skipping levels)
            prev_level = first_heading_level
            for heading in headings[1:]:
                current_level = int(heading.name[1])
                # Level can stay same, go up by 1, or go down any amount
                if current_level > prev_level:
                    assert current_level <= prev_level + 1, (
                        f"Heading level jumped from h{prev_level} to h{current_level}"
                    )
                prev_level = current_level

    def test_semantic_markup(self, research_page_html):
        """Test that semantic HTML elements are used appropriately"""
        soup = research_page_html

        # Check for semantic landmarks
        main_content = soup.find(
            ["main", "div"], class_=re.compile(r"(content|main)")
        )
        assert main_content is not None, "Should have main content area"

        # Check that buttons are actually button elements
        submit_button = soup.find("button", {"id": "start-research-btn"})
        assert submit_button is not None, "Submit should be a button element"
        assert submit_button.get("type") == "submit", (
            "Submit button should have type='submit'"
        )

    def test_required_fields_marked(self, research_page_html):
        """Test that required fields are properly marked"""
        soup = research_page_html

        # The query textarea should be required (if it has required attribute)
        query_field = soup.find("textarea", {"id": "query"})
        assert query_field is not None, "Should have query textarea"

        # If required attribute is present, it should be properly marked
        if query_field.get("required"):
            # Should have aria-required or required attribute
            assert query_field.get(
                "aria-required"
            ) == "true" or query_field.has_attr("required"), (
                "Required fields should be marked with aria-required or required attribute"
            )

    def test_error_handling_structure(self, research_page_html):
        """Test that error display areas are properly structured"""
        soup = research_page_html

        # Check for alert container
        alert_container = soup.find("div", {"id": "research-alert"})
        assert alert_container is not None, (
            "Should have alert container for error messages"
        )

        # Container should have proper ARIA role or be ready for dynamic content
        # When alerts are shown, they should have role="alert" or aria-live region


class TestAccessibilityConfiguration:
    """Test accessibility-related configuration and setup"""

    def test_html_lang_attribute(self, base_url):
        """Test that HTML has proper lang attribute"""
        response = requests.get(urljoin(base_url, "/research/"))
        response.raise_for_status()
        soup = BeautifulSoup(response.content, "html.parser")

        html_element = soup.find("html")
        assert html_element is not None, "Should have html element"

        lang = html_element.get("lang")
        assert lang is not None, "HTML element should have lang attribute"
        assert lang.startswith("en"), "Language should be English (en)"

    def test_viewport_meta_tag(self, base_url):
        """Test that viewport meta tag is present for mobile accessibility"""
        response = requests.get(urljoin(base_url, "/research/"))
        response.raise_for_status()
        soup = BeautifulSoup(response.content, "html.parser")

        viewport_meta = soup.find("meta", {"name": "viewport"})
        assert viewport_meta is not None, "Should have viewport meta tag"

        content = viewport_meta.get("content", "")
        assert "width=device-width" in content, (
            "Viewport should include width=device-width"
        )
        assert "initial-scale=1" in content, (
            "Viewport should include initial-scale=1"
        )

    def test_css_focus_styles(self, base_url):
        """Test that CSS includes focus styles (basic check)"""
        # This is a basic test - ideally we'd parse CSS files
        # For now, we just check that custom CSS files are loaded
        response = requests.get(urljoin(base_url, "/research/"))
        response.raise_for_status()
        soup = BeautifulSoup(response.content, "html.parser")

        css_links = soup.find_all("link", {"rel": "stylesheet"})
        css_hrefs = [link.get("href", "") for link in css_links]

        # Check that our custom CSS file is loaded
        custom_css_loaded = any(
            "custom_dropdown.css" in href for href in css_hrefs
        )
        assert custom_css_loaded, "Custom dropdown CSS should be loaded"


@pytest.fixture
def base_url():
    """Base URL for the application"""
    # This should be configured based on your test environment
    import os

    return os.getenv("TEST_BASE_URL", "http://localhost:5000")


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
