"""Text extraction from various output formats.

This module provides a singledispatch-based extractor for converting
polymorphic tool outputs into plain text strings.

The singledispatch pattern follows the existing pattern in
terminaluse.lib.utils.completions for type-specific handling.

Example:
    output = [{"type": "text", "text": "Hello"}, {"type": "text", "text": "World"}]
    text = extract_text(output)
    # text: "Hello\\nWorld"
"""

from __future__ import annotations

from functools import singledispatch
from typing import Any


@singledispatch
def extract_text(output: Any) -> str:
    """Extract text content from various output formats.

    Uses singledispatch for type-specific handling.

    Supported types:
        - str: Returned as-is
        - list: Extracts "text" fields from dicts, joins with newlines
        - dict: Extracts "text" field if present

    Fallback: str(output) for unknown types.

    Args:
        output: The output to extract text from.

    Returns:
        Extracted text as a string.
    """
    return str(output)


@extract_text.register(str)
def _extract_str(output: str) -> str:
    """Strings are returned as-is."""
    return output


@extract_text.register(list)
def _extract_list(output: list) -> str:
    """Extract text from list of parts.

    Handles formats like:
        [{"type": "text", "text": "content"}, ...]
        ["plain string", ...]
        Mixed lists of dicts and strings
    """
    texts: list[str] = []

    for part in output:
        if isinstance(part, dict) and "text" in part:
            texts.append(str(part["text"]))
        elif isinstance(part, str):
            texts.append(part)
        # Skip non-text parts (e.g., {"type": "image", ...})

    return "\n".join(texts) if texts else ""


@extract_text.register(dict)
def _extract_dict(output: dict) -> str:
    """Extract text from a dict.

    Looks for text content in priority order:
    1. "text" - standard text field
    2. "aggregated_output" - Codex command_execution output
    3. "result" - Codex mcp_tool_call result
    4. "output" - generic output field

    Falls back to str() for unknown formats.
    """
    if "text" in output:
        return str(output["text"])

    if "aggregated_output" in output:
        return str(output["aggregated_output"])

    if "result" in output:
        result = output["result"]
        if isinstance(result, str):
            return result
        return extract_text(result)

    if "output" in output:
        inner = output["output"]
        if isinstance(inner, str):
            return inner
        return extract_text(inner)

    return str(output)
