"""
OpenAI API 응답/요청 처리 유틸리티
"""

from typing import Any, Dict, Optional
from ..._internal.utils import safe_extract_attr, format_messages
from .types import RequestParams, ResponseContent, UsageInfo


def extract_request_params(
    kwargs: Dict[str, Any],
    is_responses: bool = False,
) -> RequestParams:
    """
    요청 파라미터를 추출합니다.

    Args:
        kwargs: API 호출 키워드 인자
        is_responses: Responses API 여부

    Returns:
        추출된 요청 파라미터
    """
    if is_responses:
        # Responses API (2024) 파라미터
        return RequestParams(
            model=kwargs.get("model", "unknown"),
            input=kwargs.get("input", []),
            temperature=kwargs.get("temperature"),
            max_output_tokens=kwargs.get("max_output_tokens"),
            top_p=kwargs.get("top_p"),
            presence_penalty=kwargs.get("presence_penalty"),
            frequency_penalty=kwargs.get("frequency_penalty"),
            stop=kwargs.get("stop"),
            metadata=kwargs.get("metadata"),
            stream=kwargs.get("stream", False),
        )

    # Chat Completions API 파라미터
    return RequestParams(
        model=kwargs.get("model", "unknown"),
        messages=kwargs.get("messages", []),
        temperature=kwargs.get("temperature"),
        max_tokens=kwargs.get("max_tokens"),
        max_completion_tokens=kwargs.get("max_completion_tokens"),
        top_p=kwargs.get("top_p"),
        frequency_penalty=kwargs.get("frequency_penalty"),
        presence_penalty=kwargs.get("presence_penalty"),
        n=kwargs.get("n", 1),
        stream=kwargs.get("stream", False),
        stop=kwargs.get("stop"),
        tools=kwargs.get("tools"),
        tool_choice=kwargs.get("tool_choice"),
        response_format=kwargs.get("response_format"),
        seed=kwargs.get("seed"),
        logprobs=kwargs.get("logprobs"),
        top_logprobs=kwargs.get("top_logprobs"),
        user=kwargs.get("user"),
    )


def format_prompt(request_params: RequestParams, is_responses: bool) -> str:
    """
    요청 파라미터에서 prompt를 추출합니다.

    Args:
        request_params: 요청 파라미터
        is_responses: Responses API 여부

    Returns:
        포맷된 prompt 문자열
    """
    if is_responses:
        return format_messages(request_params.get("input", []))
    return format_messages(request_params.get("messages", []))


def extract_response_content(response: Any) -> ResponseContent:
    """
    Chat Completions API 응답에서 텍스트, tool calls, logprobs 등을 추출합니다.

    Args:
        response: OpenAI API 응답 객체

    Returns:
        추출된 응답 내용
    """
    result = ResponseContent(
        text="",
        tool_calls=None,
        logprobs=None,
    )

    try:
        if not hasattr(response, "choices") or not response.choices:
            return result

        first_choice = response.choices[0]
        message = first_choice.message

        # 텍스트 응답
        if hasattr(message, "content") and message.content:
            result["text"] = message.content

        # Tool calls
        if hasattr(message, "tool_calls") and message.tool_calls:
            result["tool_calls"] = [
                {
                    "id": tc.id,
                    "type": tc.type,
                    "function": {
                        "name": tc.function.name,
                        "arguments": tc.function.arguments,
                    },
                }
                for tc in message.tool_calls
            ]

        # Logprobs
        if hasattr(first_choice, "logprobs") and first_choice.logprobs:
            result["logprobs"] = serialize_logprobs(first_choice.logprobs)

    except Exception:
        pass

    return result


def extract_responses_content(response: Any) -> ResponseContent:
    """
    Responses API 응답에서 텍스트와 tool calls를 추출합니다.

    Args:
        response: OpenAI Responses API 응답 객체

    Returns:
        추출된 응답 내용
    """
    result = ResponseContent(
        text="",
        tool_calls=None,
        logprobs=None,
    )

    try:
        # 우선 output_text 속성 활용
        if hasattr(response, "output_text") and response.output_text:
            result["text"] = response.output_text

        # output 리스트 구조 탐색
        if hasattr(response, "output") and response.output:
            for output_item in response.output:
                # ResponseFunctionToolCall 타입인 경우 (tool call)
                if hasattr(output_item, "type") and output_item.type == "function_call":
                    if result["tool_calls"] is None:
                        result["tool_calls"] = []

                    tool_call = {
                        "id": getattr(output_item, "call_id", ""),
                        "type": "function",
                        "function": {
                            "name": getattr(output_item, "name", ""),
                            "arguments": getattr(output_item, "arguments", "{}"),
                        },
                    }
                    result["tool_calls"].append(tool_call)

                # content 배열 처리 (텍스트 응답)
                elif hasattr(output_item, "content") and output_item.content:
                    for content_item in output_item.content:
                        # 텍스트 추출
                        if hasattr(content_item, "type") and content_item.type == "text":
                            if hasattr(content_item, "text"):
                                text_val = (
                                    getattr(content_item.text, "value", None) or content_item.text
                                )
                                if text_val and isinstance(text_val, str):
                                    result["text"] += text_val

        # choices/message 스타일이 있다면 재사용 (fallback)
        if not result["text"] and not result["tool_calls"] and hasattr(response, "choices"):
            return extract_response_content(response)

    except Exception:
        pass

    return result


def extract_detailed_usage(response: Any) -> UsageInfo:
    """
    상세한 토큰 사용량을 추출합니다.
    Chat Completions API와 Responses API 모두 지원합니다.

    Args:
        response: OpenAI API 응답 객체

    Returns:
        토큰 사용량 정보
    """
    usage = UsageInfo()

    try:
        if hasattr(response, "usage") and response.usage:
            usage_obj = response.usage

            # Responses API uses input_tokens/output_tokens
            input_tokens = safe_extract_attr(usage_obj, "input_tokens", default=None)
            output_tokens = safe_extract_attr(usage_obj, "output_tokens", default=None)
            
            if input_tokens is not None:
                # Responses API format
                usage["prompt_tokens"] = input_tokens
                usage["completion_tokens"] = output_tokens or 0
                usage["total_tokens"] = safe_extract_attr(usage_obj, "total_tokens", default=0)
                
                # Responses API detailed tokens
                if hasattr(usage_obj, "output_tokens_details") and usage_obj.output_tokens_details:
                    details = usage_obj.output_tokens_details
                    usage["reasoning_tokens"] = safe_extract_attr(
                        details, "reasoning_tokens", default=0
                    )
                
                if hasattr(usage_obj, "input_tokens_details") and usage_obj.input_tokens_details:
                    details = usage_obj.input_tokens_details
                    usage["cached_tokens"] = safe_extract_attr(details, "cached_tokens", default=0)
            else:
                # Chat Completions API format
                usage["prompt_tokens"] = safe_extract_attr(usage_obj, "prompt_tokens", default=0)
                usage["completion_tokens"] = safe_extract_attr(
                    usage_obj, "completion_tokens", default=0
                )
                usage["total_tokens"] = safe_extract_attr(usage_obj, "total_tokens", default=0)

                # O1 모델의 reasoning tokens
                if hasattr(usage_obj, "completion_tokens_details"):
                    details = usage_obj.completion_tokens_details
                    if details:
                        usage["reasoning_tokens"] = safe_extract_attr(
                            details, "reasoning_tokens", default=0
                        )
                        usage["accepted_prediction_tokens"] = safe_extract_attr(
                            details, "accepted_prediction_tokens", default=0
                        )
                        usage["rejected_prediction_tokens"] = safe_extract_attr(
                            details, "rejected_prediction_tokens", default=0
                        )

                # Prompt tokens 상세
                if hasattr(usage_obj, "prompt_tokens_details"):
                    details = usage_obj.prompt_tokens_details
                    if details:
                        usage["cached_tokens"] = safe_extract_attr(details, "cached_tokens", default=0)
                        usage["audio_tokens"] = safe_extract_attr(details, "audio_tokens", default=0)

    except Exception:
        pass

    return usage


def serialize_logprobs(logprobs: Any) -> Optional[Dict[str, Any]]:
    """
    Logprobs를 직렬화 가능한 형태로 변환합니다.

    Args:
        logprobs: Logprobs 객체

    Returns:
        직렬화된 logprobs 또는 None
    """
    try:
        # Pydantic 모델을 dict로 변환
        if hasattr(logprobs, "model_dump"):
            return logprobs.model_dump()
        elif hasattr(logprobs, "dict"):
            return logprobs.dict()
        else:
            return str(logprobs)
    except Exception:
        return None


def extract_finish_reason(response: Any, is_responses: bool) -> Optional[str]:
    """
    완료 이유를 추출합니다.

    Args:
        response: OpenAI API 응답 객체
        is_responses: Responses API 여부

    Returns:
        완료 이유 문자열 또는 None
    """
    if is_responses:
        # Responses API uses 'status' field instead of 'finish_reason'
        # status can be: completed, failed, in_progress, cancelled, queued, incomplete
        status = safe_extract_attr(response, "status", default=None)
        if status:
            # Map status to finish_reason-like values for consistency
            status_map = {
                "completed": "stop",
                "incomplete": "length",
                "failed": "error",
                "cancelled": "cancelled",
                "in_progress": "in_progress",
                "queued": "queued",
            }
            return status_map.get(status, status)
        return None

    choices = safe_extract_attr(response, "choices", default=[])
    if choices and len(choices) > 0:
        return safe_extract_attr(choices[0], "finish_reason", default=None)

    return None
