"""
OpenAI Responses API format adapter and input conversion helper
"""

import json
from typing import List, Dict, Any, Optional, Union
from .base import FormatAdapter
from ..client.types import MessagesType, ToolsType, ResultType

from openai.types.responses.response import Response
from openai.types.responses.response_output_message import ResponseOutputMessage
from openai.types.responses.response_function_tool_call import ResponseFunctionToolCall
from openai.types.responses.response_output_text import (
    AnnotationURLCitation,
    ResponseOutputText,
)
from openai.types.responses.response_reasoning_item import ResponseReasoningItem
from openai.types.responses.easy_input_message import EasyInputMessage
from openai.types.responses.response_input_item import FunctionCallOutput


class OpenAIResponsesAdapter(FormatAdapter):
    """Adapter for OpenAI Responses API format"""

    def can_handle(self, result: ResultType) -> bool:
        return isinstance(result, Response)

    def process_result(
        self,
        messages: MessagesType,
        result: ResultType,
        system: Optional[str] = None,
        tools: ToolsType = None,
    ) -> tuple[List[Dict[str, Any]], Optional[str], Optional[List[Dict[str, Any]]]]:
        if not self.can_handle(result):
            return messages, system, tools

        last_builtin_tool_id: Optional[str] = None
        for item in result.output:
            if isinstance(item, ResponseOutputMessage):
                text_parts: List[str] = []
                url_citations: List[Dict[str, Any]] = []
                for content_part in item.content:
                    if isinstance(content_part, ResponseOutputText):
                        text_parts.append(content_part.text)
                        for ann in content_part.annotations:
                            if isinstance(ann, AnnotationURLCitation):
                                url_citations.append(
                                    {"url": ann.url, "title": ann.title}
                                )
                if url_citations and last_builtin_tool_id is not None:
                    messages.append(
                        {
                            "role": "tool",
                            "tool_call_id": last_builtin_tool_id,
                            "content": json.dumps(url_citations),
                        }
                    )
                messages.append({"role": "assistant", "content": "\n".join(text_parts)})
            elif isinstance(item, ResponseFunctionToolCall):
                messages.append(
                    {
                        "role": "assistant",
                        "content": None,
                        "tool_calls": [
                            {
                                "id": item.call_id,
                                "type": "function",
                                "function": {
                                    "name": item.name,
                                    "arguments": item.arguments,
                                },
                            }
                        ],
                    }
                )
            elif not isinstance(item, ResponseReasoningItem):
                # Generic built-in tool (web_search_call, code_interpreter_call,
                # file_search_call, computer_call, or any future type)
                data = item.model_dump(exclude_none=True)
                item_id = data.get("call_id") or data.get("id", "")
                tool_name = data.get("type", "unknown_tool")
                messages.append(
                    {
                        "role": "assistant",
                        "content": None,
                        "tool_calls": [
                            {
                                "id": item_id,
                                "type": "function",
                                "function": {
                                    "name": tool_name,
                                    "arguments": json.dumps(data),
                                },
                            }
                        ],
                    }
                )
                last_builtin_tool_id = item_id

        return messages, system, tools


def responses_input_to_messages(
    input: Union[str, List[Any]],
) -> List[Dict[str, Any]]:
    """Convert an OpenAI Responses API input to the standard chat messages format.

    Use this to build the ``messages`` argument when calling ``evaluate()`` after
    a Responses API call::

        response = openai_client.responses.create(model="gpt-4o", input=user_input)
        result = composo_client.evaluate(
            messages=responses_input_to_messages(user_input),
            result=response,
            criteria="...",
        )

    Args:
        input: The value passed as ``input`` to ``client.responses.create()``.
               Can be a plain string or a list of input items.

    Returns:
        A list of chat message dicts in the standard ``{"role": ..., "content": ...}``
        format understood by Composo evaluation.
    """
    if isinstance(input, str):
        return [{"role": "user", "content": input}]

    messages: List[Dict[str, Any]] = []
    for item in input:
        # EasyInputMessage: {"role": ..., "content": ..., "type": "message"}
        if isinstance(item, EasyInputMessage):
            messages.append({"role": item.role, "content": item.content})
        # Plain dict with role/content (e.g. constructed manually)
        elif isinstance(item, dict) and "role" in item and "content" in item:
            messages.append({"role": item["role"], "content": item["content"]})
        # FunctionCallOutput: tool result item
        elif isinstance(item, FunctionCallOutput):
            messages.append(
                {
                    "role": "tool",
                    "tool_call_id": item.call_id,
                    "content": item.output,
                }
            )
        # ResponseOutputMessage (assistant message passed back as input in multi-turn)
        elif isinstance(item, ResponseOutputMessage):
            text_parts = [
                part.text
                for part in item.content
                if isinstance(part, ResponseOutputText)
            ]
            messages.append({"role": "assistant", "content": "\n".join(text_parts)})
        # ResponseFunctionToolCall (tool call passed back as input in multi-turn)
        elif isinstance(item, ResponseFunctionToolCall):
            messages.append(
                {
                    "role": "assistant",
                    "content": None,
                    "tool_calls": [
                        {
                            "id": item.call_id,
                            "type": "function",
                            "function": {
                                "name": item.name,
                                "arguments": item.arguments,
                            },
                        }
                    ],
                }
            )

    return messages
