# Browser API Reference

The main entry point for browser automation.

## Constructor

```python
from browser_hybrid import Browser

browser = Browser(
    host="localhost",        # Chrome debug host
    port=9222,               # Chrome debug port
    timeout=30.0,            # Default timeout in seconds
    reconnect=True,          # Auto-reconnect on disconnect
    reconnect_max_retries=5, # Max reconnection attempts
    reconnect_backoff=0.5,   # Base backoff in seconds
    reconnect_callback=None, # Callback for reconnection events
)
```

## Tab Management

### list_tabs()

List all open tabs.

```python
tabs = browser.list_tabs()
for tab in tabs:
    print(f"{tab.id}: {tab.url} - {tab.title}")
```

Returns: `list[Tab]`

### new_tab()

Create a new tab.

```python
tab = browser.new_tab("https://example.com")
```

Parameters:
- `url` (str): URL to navigate to
- `timeout` (float, optional): Operation timeout

Returns: `Tab`

### activate_tab()

Switch to a tab.

```python
browser.activate_tab(tab)
```

Parameters:
- `tab` (Tab): Tab to activate

Returns: `bool`

### close_tab()

Close a tab.

```python
browser.close_tab(tab)
```

Parameters:
- `tab` (Tab): Tab to close

Returns: `bool`

### temp_tab()

Create a temporary tab for isolated workflows using a context manager.

```python
# Auto-close after workflow
with browser.temp_tab("https://example.com") as tab:
    browser.click_by_text("Submit")
# Tab closed automatically

# Keep tab after workflow
with browser.temp_tab("https://example.com", close_on_exit=False) as tab:
    browser.type_by_name("Email", "user@example.com")
# Tab remains open for further inspection
```

Parameters:
- `url` (str): Initial URL (default: "about:blank")
- `close_on_exit` (bool): Close tab when context exits (default: True)

Returns: Context manager yielding `Tab`

### switch_to_tab()

Switch to a specific tab, optionally focusing browser window.

```python
tabs = browser.list_tabs()
previous = browser.switch_to_tab(tabs[1])
# Work on tabs[1]
browser.switch_to_tab(previous)  # Return to first tab
```

Parameters:
- `tab` (Tab | str): Tab object or ID to switch to
- `focus` (bool): Also bring Chrome window to foreground (default: True)

Returns: `Tab | None` — Previous tab (for switching back)

## Navigation

### navigate()

Navigate to a URL.

```python
browser.navigate("https://example.com")
browser.navigate("https://example.com", tab=tab)
```

Parameters:
- `url` (str): URL to navigate to
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

### wait_for_load_state()

Wait for page load state.

```python
browser.wait_for_load_state("complete")
browser.wait_for_load_state("DOMContentLoaded")
```

Parameters:
- `state` (str): "load", "DOMContentLoaded", or "complete"
- `timeout` (float, optional): Wait timeout

Returns: `bool`

## Accessibility Tree

### accessibility_tree()

Get the accessibility tree.

```python
tree = browser.accessibility_tree()
print(tree.to_tree_str())
```

Parameters:
- `tab` (Tab, optional): Target tab

Returns: `AXNode`

### AXNode Methods

```python
# Find by role
buttons = tree.find_by_role("button")
links = tree.find_by_role("link")
headings = tree.find_by_role("heading")

# Find by name/text
elements = tree.find_by_name("Submit")

# Find by ref
node = tree.find("42")

# Find interactive elements
interactive = tree.find_interactive()

# Get tree structure
print(tree.to_tree_str())

# Convert to dict
d = tree.to_dict()
```

## Click

### click()

Click an element by ref.

```python
browser.click("42")
browser.click("42", double=True)
browser.click("42", button="right")
```

Parameters:
- `ref` (str): Accessibility reference
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout
- `double` (bool): Double-click
- `button` (str): "left", "right", or "middle"

Returns: `bool`

### click_by_text()

Click an element by visible text.

```python
browser.click_by_text("Sign in")
```

Parameters:
- `text` (str): Visible text to click
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

## Type

### type_text()

Type text into an element.

```python
browser.type_text("42", "Hello")
```

Parameters:
- `ref` (str): Accessibility reference
- `text` (str): Text to type
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

### type_by_name() — Enhanced

Type into an element by its name attribute, placeholder, label text, or ID. 

```python
browser.type_by_name("Email", "user@example.com")
browser.type_by_name("Search query", "python browser automation")
```

**Detection strategies (in order):**
1. `<label for="id">` explicit association
2. Nested `<label>Text <input></label>`
3. `placeholder` attribute match (partial and case-insensitive)
4. `aria-label` attribute
5. `aria-labelledby` reference
6. `name` or `id` attribute fallback

Parameters:
- `name` (str): Element identifier (label text, placeholder, name, or ID)
- `text` (str): Text to type
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool` — True if element found and text typed

### _find_form_element()

*Internal helper used for robust element targeting.*

Finds an accessibility reference (`ref`) for a form element based on human-readable identifiers.

```python
ref = browser._find_form_element("Email")
if ref:
    browser.click(ref)
```

Parameters:
- `identifier` (str): Label, placeholder, or name.
- `tab` (Tab, optional): Target tab.
- `timeout` (float, optional): Operation timeout.

Returns: `str | None` — Accessibility reference (`axnode@ID`) if found.

### type_slowly()

Type character by character with delay.

```python
browser.type_slowly("42", "Hello", delay=0.05)
```

Parameters:
- `ref` (str): Accessibility reference
- `text` (str): Text to type
- `delay` (float): Delay between characters (default: 0.05)
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

## Keyboard

### press_key()

Press a key or key combination.

```python
browser.press_key("Enter")
browser.press_key("c", modifiers=["Control"])
```

Parameters:
- `key` (str): Key to press
- `modifiers` (list[str], optional): ["Control", "Shift", "Alt", "Meta"]
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

## Mouse

### hover()

Hover over an element.

```python
browser.hover("42")
```

Parameters:
- `ref` (str): Accessibility reference
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

## Form Filling

### fill_form()

Fill multiple form fields.

```python
browser.fill_form({
    "Email": "user@example.com",
    "Password": "secret"
})
```

Parameters:
- `fields` (dict[str, str]): Field name/value pairs
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout
- `raise_on_error` (bool): Raise on field failure (default: False)

Returns: `dict[str, bool]` — Success/failure per field

## Wait Conditions

### wait_for()

Wait for condition.

```python
# Wait for selector
browser.wait_for(selector="#loading")

# Wait for text
browser.wait_for(text="Welcome")

# Wait for URL
browser.wait_for(url="https://example.com/success")
```

Parameters:
- `selector` (str, optional): CSS selector
- `text` (str, optional): Text to appear
- `url` (str, optional): URL pattern (regex supported)
- `timeout` (float, optional): Wait timeout

Returns: `bool`

### wait_until()

Wait for custom condition.

```python
browser.wait_until(lambda: browser.evaluate("document.readyState") == "complete")
```

Parameters:
- `condition` (callable): Function that returns True when satisfied
- `timeout` (float, optional): Wait timeout
- `interval` (float, optional): Poll interval (default: 0.1)

Returns: `bool`

## Content

### get_html()

Get page HTML.

```python
html = browser.get_html()
```

Parameters:
- `tab` (Tab, optional): Target tab

Returns: `str`

### evaluate()

Execute JavaScript.

```python
title = browser.evaluate("document.title")
url = browser.evaluate("window.location.href")
```

Parameters:
- `script` (str): JavaScript to execute
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `Any` — Script result

### screenshot()

Take screenshot.

```python
browser.screenshot("/tmp/page.png")
```

Parameters:
- `path` (str): Output path
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout

Returns: `bool`

### pdf()

Generate PDF from the current page.

```python
browser.goto("https://example.com")
browser.pdf("output.pdf")
```

With options:

```python
browser.pdf(
    "report.pdf",
    landscape=True,          # Landscape orientation
    print_background=True,   # Include background graphics
    paper_width=8.5,
    paper_height=11.0,
    margin_top=0.4,
    margin_bottom=0.4,
    scale=1.0,
)
```

Parameters:
- `path` (str): File path to save PDF
- `tab` (Tab, optional): Target tab
- `timeout` (float, optional): Operation timeout
- `landscape` (bool): Page orientation (default: False/portrait)
- `paper_width` (float): Paper width in inches (default: 8.5)
- `paper_height` (float): Paper height in inches (default: 11)
- `margin_top/bottom/left/right` (float): Margins in inches (default: 0.4)
- `print_background` (bool): Print background graphics (default: False)
- `scale` (float): Scale factor (default: 1.0)
- `page_ranges` (str): Pages to print, e.g., "1-5, 9" (default: all)
- `header_template` (str): HTML template for header
- `footer_template` (str): HTML template for footer
- `prefer_css_page_size` (bool): Use CSS @page size (default: False)

Returns: `str` — Path to saved PDF file

## Cookies

### get_cookies()

Get all cookies.

```python
cookies = browser.get_cookies()
```

Parameters:
- `urls` (list[str], optional): Filter by URLs
- `tab` (Tab, optional): Target tab

Returns: `list[dict]`

### set_cookies()

Set cookies.

```python
browser.set_cookies([{
    "name": "session",
    "value": "abc123",
    "domain": ".example.com"
}])
```

### delete_cookies()

Delete cookies.

```python
browser.delete_cookies("session")
browser.delete_cookies()  # Delete all
```

## Network

### on_request()

Monitor requests.

```python
browser.on_request(lambda req: print(req['request']['url']))
```

### on_response()

Monitor responses.

```python
browser.on_response(lambda res: print(res['response']['status']))
```

### on_request_failed()

Monitor failed requests.

```python
browser.on_request_failed(lambda req: print(f"Failed: {req}"))
```

## Connection

### is_connected()

Check connection status.

```python
if browser.is_connected():
    print("Connected")
```

Returns: `bool`

### close()

Close browser connection.

```python
browser.close()
```

Returns: `None`

## Recording & Playback

### start_recording()

Start recording browser actions.

```python
browser.start_recording("session.json")
# ... perform actions ...
browser.stop_recording()
```

Parameters:
- `path` (str | None): Path to save recording (default: temp file)

Returns: `Recording` object

### stop_recording()

Stop recording and save to file.

```python
path = browser.stop_recording()
print(f"Recording saved to {path}")
```

Returns: `str` — Path to saved recording file

Raises: `ValueError` if no recording is in progress.

### playback()

Replay recorded browser actions.

```python
browser.playback("session.json", speed=2.0, verify=True)
```

Parameters:
- `recording` (Recording | str): Recording object or path to JSON file
- `speed` (float): Playback speed multiplier (default: 1.0)
- `verify` (bool): If True, raises BrowserError if an action fails (returned False) (default: False)

Returns: `bool` — True if playback completed successfully

### pause_recording()

Temporarily pause action recording.

### resume_recording()

Resume a paused recording session.

### get_recording()

Get the current active `Recording` object.

Returns: `Recording | None`

## Visual Regression

### compare_screenshots()

Compare two screenshots pixel-by-pixel.

```python
result = browser.compare_screenshots("baseline.png", "current.png")
if not result.match:
    print(f"Images differ by {result.diff_percentage:.2f}%")
```

Parameters:
- `baseline` (str): Path to baseline screenshot
- `current` (str): Path to current screenshot
- `threshold` (float): Allowed difference percentage (default: 0.0)
- `output_diff` (str | None): Path to save diff image (default: None)
- `region` (tuple | None): Crop region (x, y, width, height) (default: None)

Returns: `ComparisonResult`

### screenshot_and_compare()

Take screenshot and compare against baseline in one call.

```python
result = browser.screenshot_and_compare("current.png", "baseline.png", threshold=0.01)
```

Parameters:
- `path` (str): Path to save current screenshot
- `baseline` (str): Path to baseline screenshot
- `threshold` (float): Allowed difference percentage (default: 0.0)
- `output_diff` (str | None): Path to save diff image (default: None)
- `region` (tuple | None): Crop region (x, y, width, height) (default: None)

Returns: `ComparisonResult`

### assert_visual_match()

Assert current page matches baseline screenshot.

```python
browser.assert_visual_match("baseline.png", threshold=0.01)
```

Parameters:
- `baseline` (str): Path to baseline screenshot
- `threshold` (float): Allowed difference percentage (default: 0.0)
- `update_baseline` (bool): Update baseline if mismatch (default: False)
- `region` (tuple | None): Crop region (x, y, width, height) (default: None)

Returns: `ComparisonResult`

Raises: `AssertionError` if images differ beyond threshold.