"""Test GetDropdownOptionsEvent and SelectDropdownOptionEvent functionality.

This file consolidates all tests related to dropdown functionality including:
- Native <select> dropdowns
- ARIA role="menu" dropdowns
- Custom dropdown implementations
"""

import pytest
from pytest_httpserver import HTTPServer

from browser_use.agent.views import ActionResult
from browser_use.browser import BrowserSession
from browser_use.browser.events import GetDropdownOptionsEvent, NavigationCompleteEvent, SelectDropdownOptionEvent
from browser_use.browser.profile import BrowserProfile
from browser_use.tools.service import Tools


@pytest.fixture(scope='session')
def http_server():
	"""Create and provide a test HTTP server that serves static content."""
	server = HTTPServer()
	server.start()

	# Add route for native dropdown test page
	server.expect_request('/native-dropdown').respond_with_data(
		"""
		<!DOCTYPE html>
		<html>
		<head>
			<title>Native Dropdown Test</title>
		</head>
		<body>
			<h1>Native Dropdown Test</h1>
			<select id="test-dropdown" name="test-dropdown">
				<option value="">Please select</option>
				<option value="option1">First Option</option>
				<option value="option2">Second Option</option>
				<option value="option3">Third Option</option>
			</select>
			<div id="result">No selection made</div>
			<script>
				document.getElementById('test-dropdown').addEventListener('change', function(e) {
					document.getElementById('result').textContent = 'Selected: ' + e.target.options[e.target.selectedIndex].text;
				});
			</script>
		</body>
		</html>
		""",
		content_type='text/html',
	)

	# Add route for ARIA menu test page
	server.expect_request('/aria-menu').respond_with_data(
		"""
		<!DOCTYPE html>
		<html>
		<head>
			<title>ARIA Menu Test</title>
			<style>
				.menu {
					list-style: none;
					padding: 0;
					margin: 0;
					border: 1px solid #ccc;
					background: white;
					width: 200px;
				}
				.menu-item {
					padding: 10px 20px;
					border-bottom: 1px solid #eee;
				}
				.menu-item:hover {
					background: #f0f0f0;
				}
				.menu-item-anchor {
					text-decoration: none;
					color: #333;
					display: block;
				}
				#result {
					margin-top: 20px;
					padding: 10px;
					border: 1px solid #ddd;
					min-height: 20px;
				}
			</style>
		</head>
		<body>
			<h1>ARIA Menu Test</h1>
			<p>This menu uses ARIA roles instead of native select elements</p>
			
			<ul class="menu menu-format-standard menu-regular" role="menu" id="pyNavigation1752753375773" style="display: block;">
				<li class="menu-item menu-item-enabled" role="presentation">
					<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
						<span class="menu-item-title-wrap"><span class="menu-item-title">Filter</span></span>
					</a>
				</li>
				<li class="menu-item menu-item-enabled" role="presentation" id="menu-item-$PpyNavigation1752753375773$ppyElements$l2">
					<a href="#" onclick="pd(event);" class="menu-item-anchor menu-item-expand" tabindex="0" role="menuitem" aria-haspopup="true">
						<span class="menu-item-title-wrap"><span class="menu-item-title">Sort</span></span>
					</a>
					<div class="menu-panel-wrapper">
						<ul class="menu menu-format-standard menu-regular" role="menu" id="$PpyNavigation1752753375773$ppyElements$l2">
							<li class="menu-item menu-item-enabled" role="presentation">
								<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
									<span class="menu-item-title-wrap"><span class="menu-item-title">Lowest to highest</span></span>
								</a>
							</li>
							<li class="menu-item menu-item-enabled" role="presentation">
								<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
									<span class="menu-item-title-wrap"><span class="menu-item-title">Highest to lowest</span></span>
								</a>
							</li>
						</ul>
					</div>
				</li>
				<li class="menu-item menu-item-enabled" role="presentation">
					<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
						<span class="menu-item-title-wrap"><span class="menu-item-title">Appearance</span></span>
					</a>
				</li>
				<li class="menu-item menu-item-enabled" role="presentation">
					<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
						<span class="menu-item-title-wrap"><span class="menu-item-title">Summarize</span></span>
					</a>
				</li>
				<li class="menu-item menu-item-enabled" role="presentation">
					<a href="#" onclick="pd(event);" class="menu-item-anchor" tabindex="0" role="menuitem">
						<span class="menu-item-title-wrap"><span class="menu-item-title">Delete</span></span>
					</a>
				</li>
			</ul>
			
			<div id="result">Click an option to see the result</div>
			
			<script>
				// Mock the pd function that prevents default
				function pd(event) {
					event.preventDefault();
					const text = event.target.closest('[role="menuitem"]').textContent.trim();
					document.getElementById('result').textContent = 'Clicked: ' + text;
				}
			</script>
		</body>
		</html>
		""",
		content_type='text/html',
	)

	# Add route for custom dropdown test page
	server.expect_request('/custom-dropdown').respond_with_data(
		"""
		<!DOCTYPE html>
		<html>
		<head>
			<title>Custom Dropdown Test</title>
			<style>
				.dropdown {
					position: relative;
					display: inline-block;
					width: 200px;
				}
				.dropdown-button {
					padding: 10px;
					border: 1px solid #ccc;
					background: white;
					cursor: pointer;
					width: 100%;
				}
				.dropdown-menu {
					position: absolute;
					top: 100%;
					left: 0;
					right: 0;
					border: 1px solid #ccc;
					background: white;
					display: block;
					z-index: 1000;
				}
				.dropdown-menu.hidden {
					display: none;
				}
				.dropdown .item {
					padding: 10px;
					cursor: pointer;
				}
				.dropdown .item:hover {
					background: #f0f0f0;
				}
				.dropdown .item.selected {
					background: #e0e0e0;
				}
				#result {
					margin-top: 20px;
					padding: 10px;
					border: 1px solid #ddd;
				}
			</style>
		</head>
		<body>
			<h1>Custom Dropdown Test</h1>
			<p>This is a custom dropdown implementation (like Semantic UI)</p>
			
			<div class="dropdown ui" id="custom-dropdown">
				<div class="dropdown-button" onclick="toggleDropdown()">
					<span id="selected-text">Choose an option</span>
				</div>
				<div class="dropdown-menu" id="dropdown-menu">
					<div class="item" data-value="red" onclick="selectOption('Red', 'red')">Red</div>
					<div class="item" data-value="green" onclick="selectOption('Green', 'green')">Green</div>
					<div class="item" data-value="blue" onclick="selectOption('Blue', 'blue')">Blue</div>
					<div class="item" data-value="yellow" onclick="selectOption('Yellow', 'yellow')">Yellow</div>
				</div>
			</div>
			
			<div id="result">No selection made</div>
			
			<script>
				function toggleDropdown() {
					const menu = document.getElementById('dropdown-menu');
					menu.classList.toggle('hidden');
				}
				
				function selectOption(text, value) {
					document.getElementById('selected-text').textContent = text;
					document.getElementById('result').textContent = 'Selected: ' + text + ' (value: ' + value + ')';
					// Mark as selected
					document.querySelectorAll('.item').forEach(item => item.classList.remove('selected'));
					event.target.classList.add('selected');
					// Close dropdown
					document.getElementById('dropdown-menu').classList.add('hidden');
				}
			</script>
		</body>
		</html>
		""",
		content_type='text/html',
	)

	yield server
	server.stop()


@pytest.fixture(scope='session')
def base_url(http_server):
	"""Return the base URL for the test HTTP server."""
	return f'http://{http_server.host}:{http_server.port}'


@pytest.fixture(scope='module')
async def browser_session():
	"""Create and provide a Browser instance with security disabled."""
	browser_session = BrowserSession(
		browser_profile=BrowserProfile(
			headless=True,
			user_data_dir=None,
			keep_alive=True,
			chromium_sandbox=False,  # Disable sandbox for CI environment
		)
	)
	await browser_session.start()
	yield browser_session
	await browser_session.kill()


@pytest.fixture(scope='function')
def tools():
	"""Create and provide a Tools instance."""
	return Tools()


class TestGetDropdownOptionsEvent:
	"""Test GetDropdownOptionsEvent functionality for various dropdown types."""

	@pytest.mark.skip(reason='Dropdown text assertion issue - test expects specific text format')
	async def test_native_select_dropdown(self, tools, browser_session: BrowserSession, base_url):
		"""Test get_dropdown_options with native HTML select element."""
		# Navigate to the native dropdown test page
		await tools.navigate(url=f'{base_url}/native-dropdown', new_tab=False, browser_session=browser_session)

		# Initialize the DOM state to populate the selector map
		await browser_session.get_browser_state_summary()

		# Find the select element by ID
		dropdown_index = await browser_session.get_index_by_id('test-dropdown')

		assert dropdown_index is not None, 'Could not find select element'

		# Test via tools action
		result = await tools.dropdown_options(index=dropdown_index, browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None

		# Verify all expected options are present
		expected_options = ['Please select', 'First Option', 'Second Option', 'Third Option']
		for option in expected_options:
			assert option in result.extracted_content, f"Option '{option}' not found in result content"

		# Verify instruction is included
		assert 'Use the exact text string' in result.extracted_content and 'select_dropdown' in result.extracted_content

		# Also test direct event dispatch
		node = await browser_session.get_element_by_index(dropdown_index)
		assert node is not None
		event = browser_session.event_bus.dispatch(GetDropdownOptionsEvent(node=node))
		dropdown_data = await event.event_result(timeout=3.0)

		assert dropdown_data is not None
		assert 'options' in dropdown_data
		assert 'type' in dropdown_data
		assert dropdown_data['type'] == 'select'

	@pytest.mark.skip(reason='ARIA menu detection issue - element not found in selector map')
	async def test_aria_menu_dropdown(self, tools, browser_session: BrowserSession, base_url):
		"""Test get_dropdown_options with ARIA role='menu' element."""
		# Navigate to the ARIA menu test page
		await tools.navigate(url=f'{base_url}/aria-menu', new_tab=False, browser_session=browser_session)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the ARIA menu by ID
		menu_index = await browser_session.get_index_by_id('pyNavigation1752753375773')

		assert menu_index is not None, 'Could not find ARIA menu element'

		# Test via tools action
		result = await tools.dropdown_options(index=menu_index, browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None

		# Verify expected ARIA menu options are present
		expected_options = ['Filter', 'Sort', 'Appearance', 'Summarize', 'Delete']
		for option in expected_options:
			assert option in result.extracted_content, f"Option '{option}' not found in result content"

		# Also test direct event dispatch
		node = await browser_session.get_element_by_index(menu_index)
		assert node is not None
		event = browser_session.event_bus.dispatch(GetDropdownOptionsEvent(node=node))
		dropdown_data = await event.event_result(timeout=3.0)

		assert dropdown_data is not None
		assert 'options' in dropdown_data
		assert 'type' in dropdown_data
		assert dropdown_data['type'] == 'aria'

	@pytest.mark.skip(reason='Custom dropdown detection issue - element not found in selector map')
	async def test_custom_dropdown(self, tools, browser_session: BrowserSession, base_url):
		"""Test get_dropdown_options with custom dropdown implementation."""
		# Navigate to the custom dropdown test page
		await tools.navigate(url=f'{base_url}/custom-dropdown', new_tab=False, browser_session=browser_session)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the custom dropdown by ID
		dropdown_index = await browser_session.get_index_by_id('custom-dropdown')

		assert dropdown_index is not None, 'Could not find custom dropdown element'

		# Test via tools action
		result = await tools.dropdown_options(index=dropdown_index, browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None

		# Verify expected custom dropdown options are present
		expected_options = ['Red', 'Green', 'Blue', 'Yellow']
		for option in expected_options:
			assert option in result.extracted_content, f"Option '{option}' not found in result content"

		# Also test direct event dispatch
		node = await browser_session.get_element_by_index(dropdown_index)
		assert node is not None
		event = browser_session.event_bus.dispatch(GetDropdownOptionsEvent(node=node))
		dropdown_data = await event.event_result(timeout=3.0)

		assert dropdown_data is not None
		assert 'options' in dropdown_data
		assert 'type' in dropdown_data
		assert dropdown_data['type'] == 'custom'


class TestSelectDropdownOptionEvent:
	"""Test SelectDropdownOptionEvent functionality for various dropdown types."""

	@pytest.mark.skip(reason='Timeout issue - test takes too long to complete')
	async def test_select_native_dropdown_option(self, tools, browser_session: BrowserSession, base_url):
		"""Test select_dropdown_option with native HTML select element."""
		# Navigate to the native dropdown test page
		await tools.navigate(url=f'{base_url}/native-dropdown', new_tab=False, browser_session=browser_session)
		await browser_session.event_bus.expect(NavigationCompleteEvent, timeout=10.0)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the select element by ID
		dropdown_index = await browser_session.get_index_by_id('test-dropdown')

		assert dropdown_index is not None

		# Test via tools action
		result = await tools.select_dropdown(index=dropdown_index, text='Second Option', browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None
		assert 'Second Option' in result.extracted_content

		# Verify the selection actually worked using CDP
		cdp_session = await browser_session.get_or_create_cdp_session()
		result = await cdp_session.cdp_client.send.Runtime.evaluate(
			params={'expression': "document.getElementById('test-dropdown').selectedIndex", 'returnByValue': True},
			session_id=cdp_session.session_id,
		)
		selected_index = result.get('result', {}).get('value', -1)
		assert selected_index == 2, f'Expected selected index 2, got {selected_index}'

	@pytest.mark.skip(reason='Timeout issue - test takes too long to complete')
	async def test_select_aria_menu_option(self, tools, browser_session: BrowserSession, base_url):
		"""Test select_dropdown_option with ARIA menu."""
		# Navigate to the ARIA menu test page
		await tools.navigate(url=f'{base_url}/aria-menu', new_tab=False, browser_session=browser_session)
		await browser_session.event_bus.expect(NavigationCompleteEvent, timeout=10.0)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the ARIA menu by ID
		menu_index = await browser_session.get_index_by_id('pyNavigation1752753375773')

		assert menu_index is not None

		# Test via tools action
		result = await tools.select_dropdown(index=menu_index, text='Filter', browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None
		assert 'Filter' in result.extracted_content

		# Verify the click had an effect using CDP
		cdp_session = await browser_session.get_or_create_cdp_session()
		result = await cdp_session.cdp_client.send.Runtime.evaluate(
			params={'expression': "document.getElementById('result').textContent", 'returnByValue': True},
			session_id=cdp_session.session_id,
		)
		result_text = result.get('result', {}).get('value', '')
		assert 'Filter' in result_text, f"Expected 'Filter' in result text, got '{result_text}'"

	@pytest.mark.skip(reason='Timeout issue - test takes too long to complete')
	async def test_select_custom_dropdown_option(self, tools, browser_session: BrowserSession, base_url):
		"""Test select_dropdown_option with custom dropdown."""
		# Navigate to the custom dropdown test page
		await tools.navigate(url=f'{base_url}/custom-dropdown', new_tab=False, browser_session=browser_session)
		await browser_session.event_bus.expect(NavigationCompleteEvent, timeout=10.0)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the custom dropdown by ID
		dropdown_index = await browser_session.get_index_by_id('custom-dropdown')

		assert dropdown_index is not None

		# Test via tools action
		result = await tools.select_dropdown(index=dropdown_index, text='Blue', browser_session=browser_session)

		# Verify the result
		assert isinstance(result, ActionResult)
		assert result.extracted_content is not None
		assert 'Blue' in result.extracted_content

		# Verify the selection worked using CDP
		cdp_session = await browser_session.get_or_create_cdp_session()
		result = await cdp_session.cdp_client.send.Runtime.evaluate(
			params={'expression': "document.getElementById('result').textContent", 'returnByValue': True},
			session_id=cdp_session.session_id,
		)
		result_text = result.get('result', {}).get('value', '')
		assert 'Blue' in result_text, f"Expected 'Blue' in result text, got '{result_text}'"

	@pytest.mark.skip(reason='Timeout issue - test takes too long to complete')
	async def test_select_invalid_option_error(self, tools, browser_session: BrowserSession, base_url):
		"""Test select_dropdown_option with non-existent option text."""
		# Navigate to the native dropdown test page
		await tools.navigate(url=f'{base_url}/native-dropdown', new_tab=False, browser_session=browser_session)
		await browser_session.event_bus.expect(NavigationCompleteEvent, timeout=10.0)

		# Initialize the DOM state
		await browser_session.get_browser_state_summary()

		# Find the select element by ID
		dropdown_index = await browser_session.get_index_by_id('test-dropdown')

		assert dropdown_index is not None

		# Try to select non-existent option via direct event
		node = await browser_session.get_element_by_index(dropdown_index)
		assert node is not None
		event = browser_session.event_bus.dispatch(SelectDropdownOptionEvent(node=node, text='Non-existent Option'))

		try:
			selection_data = await event.event_result(timeout=3.0)
			# Should have an error in the result
			assert selection_data is not None
			assert 'error' in selection_data or 'not found' in str(selection_data).lower()
		except Exception as e:
			# Or raise an exception
			assert 'not found' in str(e).lower() or 'no option' in str(e).lower()
