"""Tests for improved form detection in browser_hybrid."""

from __future__ import annotations

from unittest.mock import AsyncMock, patch

from browser_hybrid import Browser


class TestFormDetection:
    """Tests for _find_form_element and improved type_by_name/click_by_text."""

    @patch("browser_hybrid.browser.Browser._get_connection")
    @patch("browser_hybrid.browser.Browser._send_cdp")
    def test_find_form_element_by_name(self, mock_send_cdp, mock_get_conn):
        """Test finding form element by exact name attribute."""
        mock_get_conn.return_value = AsyncMock()

        # Mock CDP responses:
        # 1. Runtime.evaluate returns an object
        # 2. DOM.requestNode returns a nodeId
        # 3. DOM.describeNode returns a backendNodeId
        # 4. Accessibility.getFullAXTree returns nodes
        mock_send_cdp.side_effect = [
            {"result": {"type": "object", "objectId": "obj123"}},
            {"nodeId": 10},
            {"node": {"backendNodeId": 100}},
            {"nodes": [{"nodeId": "axnode@1", "backendDOMNodeId": 100}]},
        ]

        browser = Browser()
        ref = browser._find_form_element("email")

        assert ref == "axnode@1"

        # Verify Runtime.evaluate call contains the identifier
        calls = mock_send_cdp.call_args_list
        eval_call = [c for c in calls if c.args[1] == "Runtime.evaluate"][0]
        assert "email" in eval_call.args[2]["expression"]

    @patch("browser_hybrid.browser.Browser._get_connection")
    @patch("browser_hybrid.browser.Browser._send_cdp")
    def test_find_form_element_not_found(self, mock_send_cdp, mock_get_conn):
        """Test _find_form_element when element is not found."""
        mock_get_conn.return_value = AsyncMock()

        # Runtime.evaluate returns null (or result with no objectId)
        mock_send_cdp.return_value = {
            "result": {"type": "object", "subtype": "null", "value": None}
        }

        browser = Browser()
        ref = browser._find_form_element("nonexistent")

        assert ref is None

    @patch("browser_hybrid.browser.Browser._find_form_element")
    @patch("browser_hybrid.browser.Browser.type_text")
    def test_type_by_name_uses_helper(self, mock_type_text, mock_find_form):
        """Test that type_by_name utilizes _find_form_element helper."""
        mock_find_form.return_value = "axnode@123"
        mock_type_text.return_value = True

        browser = Browser()
        success = browser.type_by_name("email", "test@example.com")

        assert success is True
        find_call = mock_find_form.call_args
        assert find_call.args[0] == "email"
        assert find_call.kwargs.get("tab") is None
        mock_type_text.assert_called_once_with(
            "axnode@123", "test@example.com", tab=None, timeout=None
        )

    @patch("browser_hybrid.browser.Browser._get_connection")
    @patch("browser_hybrid.browser.Browser._send_cdp")
    def test_click_by_text_enhanced(self, mock_send_cdp, mock_get_conn):
        """Test click_by_text uses enhanced JS with ARIA support."""
        mock_get_conn.return_value = AsyncMock()
        mock_send_cdp.return_value = {"result": {"value": True}}

        browser = Browser()
        success = browser.click_by_text("Submit Form")

        assert success is True

        calls = mock_send_cdp.call_args_list
        eval_call = [c for c in calls if c.args[1] == "Runtime.evaluate"][0]
        js_code = eval_call.args[2]["expression"]

        # Verify enhanced JS features are present
        assert "aria-label" in js_code
        assert "aria-labelledby" in js_code
        assert "matchesText" in js_code
        assert "submit form" in js_code.lower()
