from __future__ import annotations

from openai.types.responses import ResponseOutputMessage, ResponseOutputText

from agents import Agent
from agents.exceptions import RunErrorDetails
from agents.items import ItemHelpers, MessageOutputItem
from agents.util._pretty_print import pretty_print_run_error_details


def _make_message_item(text: str | None) -> MessageOutputItem:
    msg = ResponseOutputMessage.model_construct(
        id="msg_1",
        role="assistant",
        status="completed",
        content=[ResponseOutputText.model_construct(type="output_text", text=text, annotations=[])],
    )
    agent = Agent(name="test")
    return MessageOutputItem(agent=agent, raw_item=msg)


def test_text_message_output_returns_empty_string_for_none_text():
    """text_message_output must not crash when a content item has text=None."""
    item = _make_message_item(None)
    assert ItemHelpers.text_message_output(item) == ""


def test_text_message_output_returns_text_normally():
    item = _make_message_item("hello")
    assert ItemHelpers.text_message_output(item) == "hello"


def test_text_message_outputs_handles_none_text_across_items():
    """text_message_outputs must tolerate None text in any item."""
    from agents.items import RunItem

    items: list[RunItem] = [_make_message_item(None), _make_message_item("world")]
    assert ItemHelpers.text_message_outputs(items) == "world"


def _make_output_message(text: str | None) -> ResponseOutputMessage:
    return ResponseOutputMessage.model_construct(
        id="msg_1",
        role="assistant",
        status="completed",
        content=[ResponseOutputText.model_construct(type="output_text", text=text, annotations=[])],
    )


def test_extract_last_content_returns_empty_string_for_none_text():
    """extract_last_content is declared `-> str` and must not return None even if
    the underlying ResponseOutputText.text is None (observed via LiteLLM gateways
    and ``model_construct`` paths during streaming, per items.py:714-720)."""
    msg = _make_output_message(None)
    result = ItemHelpers.extract_last_content(msg)
    assert isinstance(result, str)
    assert result == ""


def test_extract_last_content_returns_text_normally():
    msg = _make_output_message("hello")
    assert ItemHelpers.extract_last_content(msg) == "hello"


def _make_run_error_details(n_input: int = 0, n_output: int = 0) -> RunErrorDetails:
    return RunErrorDetails(
        input="hi",
        new_items=[],
        raw_responses=[],
        last_agent=Agent(name="test"),
        context_wrapper=None,  # type: ignore[arg-type]
        input_guardrail_results=[None] * n_input,  # type: ignore[list-item]
        output_guardrail_results=[None] * n_output,  # type: ignore[list-item]
    )


def test_pretty_print_run_error_details_includes_output_guardrail_count():
    """pretty_print_run_error_details must report output_guardrail_results like its siblings."""
    details = _make_run_error_details(n_input=1, n_output=2)
    text = pretty_print_run_error_details(details)
    assert "1 input guardrail result(s)" in text
    assert "2 output guardrail result(s)" in text


def test_pretty_print_run_error_details_zero_output_guardrails():
    details = _make_run_error_details(n_input=0, n_output=0)
    text = pretty_print_run_error_details(details)
    assert "0 output guardrail result(s)" in text
