"""Normalize locally produced ChatResponse objects to OpenAI Responses shape."""

from __future__ import annotations

import uuid
import time
from typing import Mapping, MutableMapping, cast

from ember.models.schemas import ChatResponse, UsageStats

ResponsesMetadata = Mapping[str, object]
ResponsesPayload = MutableMapping[str, object]
MessageContent = list[dict[str, object]]


def ensure_responses_output(
    response: ChatResponse,
    *,
    default_model: str,
    metadata: ResponsesMetadata | None = None,
) -> None:
    """Mutate ``response`` so it matches the Takumi /v1/responses contract."""

    raw_input = response.raw_output
    raw_payload = _coerce_mapping(raw_input, "raw_output")
    
    if "responses_payload" in raw_payload:
        responses_payload = _coerce_mapping(raw_payload["responses_payload"], "responses_payload")
    else:
        responses_payload = dict(raw_payload)
        raw_payload = {}

    model = _resolve_model(response, responses_payload, default_model)
    text = response.text
    response.data = text

    responses_payload["output"] = _resolve_output(response, responses_payload, metadata)
    response.output = cast(MessageContent, responses_payload["output"])

    # Standard default fields matching the Responses API schema
    responses_payload.setdefault("created_at", int(time.time()))
    responses_payload.setdefault("tools", [])
    responses_payload.setdefault("tool_choice", "auto")
    responses_payload.setdefault("metadata", {})
    responses_payload.setdefault("reasoning", {"effort": None, "summary": None})
    
    if metadata:
        responses_payload["metadata"] = _merge_metadata(
            responses_payload.get("metadata"),
            metadata,
        )

    response.response_id = _resolve_response_id(response, responses_payload)
    responses_payload.setdefault("id", response.response_id)
    responses_payload.setdefault("object", "response")
    
    if "required_action" in responses_payload:
        responses_payload["status"] = "requires_action"
    elif "status" not in responses_payload:
        responses_payload["status"] = "completed"
    
    responses_payload.setdefault("model", model)

    merged_usage = _merge_usage(responses_payload.get("usage"), response.usage)
    if merged_usage:
        responses_payload["usage"] = merged_usage

    raw_payload["responses_payload"] = responses_payload
    response.raw_output = raw_payload


def _coerce_mapping(
    value: object,
    label: str,
) -> ResponsesPayload:
    if value is None:
        return {}
    if isinstance(value, Mapping):
        return dict(value)
    raise TypeError(f"Expected mapping for {label}, received {type(value).__name__}")


def _fresh_response_id() -> str:
    return f"resp_eb_{uuid.uuid4().hex}"


def _usage_payload_from_stats(stats: UsageStats | None) -> dict[str, object] | None:
    if stats is None:
        return None

    payload: dict[str, object] = {
        "prompt_tokens": stats.prompt_tokens,
        "completion_tokens": stats.completion_tokens,
        "total_tokens": stats.total_tokens,
        "input_tokens": stats.prompt_tokens,
        "output_tokens": stats.completion_tokens,
    }
    if stats.cost_usd is not None:
        payload["cost_usd"] = stats.cost_usd
    if stats.actual_cost_usd is not None:
        payload["actual_cost_usd"] = stats.actual_cost_usd
    if stats.details:
        for key, value in stats.details.items():
            if isinstance(value, (int, float)):
                payload[key] = int(value)
    return payload


def _resolve_model(
    response: ChatResponse,
    responses_payload: ResponsesPayload,
    default_model: str,
) -> str:
    if response.model_id:
        return response.model_id
    candidate = responses_payload.get("model")
    if isinstance(candidate, str) and candidate:
        response.model_id = candidate
        return candidate
    response.model_id = default_model
    return default_model


def _resolve_output(
    response: ChatResponse,
    responses_payload: ResponsesPayload,
    metadata: ResponsesMetadata | None,
) -> MessageContent:
    if isinstance(response.output, list):
        return response.output
    payload_output = responses_payload.get("output")
    if isinstance(payload_output, list):
        return cast(MessageContent, payload_output)

    text = response.text
    message: dict[str, object] = {
        "type": "message",
        "role": "assistant",
        "status": "completed",
        "content": [{"type": "output_text", "text": text}],
    }
    if metadata:
        message["metadata"] = dict(metadata)
    return [message]


def _merge_metadata(
    existing: object,
    provided: ResponsesMetadata,
) -> dict[str, object]:
    if isinstance(existing, Mapping):
        merged = dict(existing)
        for key, value in provided.items():
            merged.setdefault(key, value)
        return merged
    return dict(provided)


def _resolve_response_id(
    response: ChatResponse,
    responses_payload: ResponsesPayload,
) -> str:
    if response.response_id:
        return response.response_id
    existing = responses_payload.get("id")
    if isinstance(existing, str) and existing:
        return existing
    fresh = _fresh_response_id()
    response.response_id = fresh
    return fresh


def _merge_usage(
    existing: object,
    stats: UsageStats | None,
) -> dict[str, object] | None:
    stats_payload = _usage_payload_from_stats(stats)
    if stats_payload is None:
        return dict(existing) if isinstance(existing, Mapping) else None
    if not isinstance(existing, Mapping):
        return stats_payload
    merged = dict(existing)
    merged.update(stats_payload)
    return merged


__all__ = ["ensure_responses_output"]
