"""Format extracted DOM elements into compact LLM-friendly text.

Produces indexed element descriptions like:
    [1] button "Submit Order" (clickable)
    [2] input[text] "Search..." placeholder="Search products" (editable)
    [3] link "My Account" href="/account"

The agent references elements by index: "click [1]" or "type [2] 'hello'"
"""

from __future__ import annotations

from typing import Any

from madpod_agent.agent.browser.dom_extractor import ExtractionResult, ExtractedElement


def format_dom_for_llm(
    result: ExtractionResult,
    *,
    max_tokens_estimate: int = 4000,
    include_page_text: bool = True,
    include_metadata: bool = True,
) -> str:
    """Format an ExtractionResult into compact text for LLM context.

    Args:
        result: The extraction result to format.
        max_tokens_estimate: Rough budget (chars / 4). Elements are dropped from
            the bottom if the output exceeds this.
        include_page_text: Include page text excerpt.
        include_metadata: Include URL, title, viewport info.

    Returns:
        Formatted string ready for LLM context injection.
    """
    parts: list[str] = []

    if include_metadata:
        parts.append(f"Page: {result.title}")
        parts.append(f"URL: {result.url}")

    if result.elements:
        parts.append(f"\nInteractive elements ({result.element_count}):")
        for el in result.elements:
            line = _format_element(el)
            parts.append(line)
    else:
        parts.append("\nNo interactive elements found on this page.")

    if include_page_text and result.page_text:
        # Truncate text to fit within budget
        remaining = max(500, max_tokens_estimate * 4 - sum(len(p) for p in parts))
        text = result.page_text[:remaining]
        parts.append(f"\nPage text:\n{text}")

    output = "\n".join(parts)

    # Final truncation if needed
    max_chars = max_tokens_estimate * 4
    if len(output) > max_chars:
        output = output[:max_chars] + "\n... (truncated)"

    return output


def format_element_brief(el: ExtractedElement) -> str:
    """Format a single element as a brief one-liner for tool results."""
    return _format_element(el)


def _format_element(el: ExtractedElement) -> str:
    """Format a single element with its index and key attributes."""
    parts: list[str] = [f"[{el.index}]"]

    # Tag + role
    tag_str = el.tag
    if el.input_type and el.tag == "input":
        tag_str = f"input[{el.input_type}]"
    if el.role and el.role not in (el.tag, ""):
        tag_str = f"{tag_str} role={el.role}"
    parts.append(tag_str)

    # Name / label
    name = _truncate(el.name, 80)
    if name:
        parts.append(f'"{name}"')

    # Key attributes in parentheses
    attrs: list[str] = []
    if el.is_clickable and not el.is_editable:
        attrs.append("clickable")
    if el.is_editable:
        attrs.append("editable")
    if el.is_disabled:
        attrs.append("disabled")
    if el.placeholder:
        attrs.append(f'placeholder="{_truncate(el.placeholder, 40)}"')
    if el.value:
        attrs.append(f'value="{_truncate(el.value, 40)}"')
    if el.href:
        attrs.append(f'href="{_truncate(el.href, 60)}"')
    if el.aria_expanded:
        attrs.append(f"expanded={el.aria_expanded}")
    if el.aria_checked:
        attrs.append(f"checked={el.aria_checked}")

    if attrs:
        parts.append(f"({', '.join(attrs)})")

    return " ".join(parts)


def build_action_context(
    result: ExtractionResult,
    action: str,
    target_index: int,
) -> str:
    """Build context string for a specific action on an element.

    Used in tool results to confirm what was clicked/typed.
    """
    el = None
    for e in result.elements:
        if e.index == target_index:
            el = e
            break

    if el is None:
        return f"Element [{target_index}] not found in current page state."

    return f"{action} on {format_element_brief(el)} at ({int(el.bounds.center_x)}, {int(el.bounds.center_y)})"


def _truncate(text: str, max_len: int) -> str:
    """Truncate text with ellipsis."""
    clean = (text or "").strip().replace("\n", " ").replace("\r", "")
    if len(clean) <= max_len:
        return clean
    return clean[: max_len - 1] + "\u2026"
