"""Chat Completions protocol SSE parsing for streaming."""

from typing import Any

from celeste.io import FinishReason

from .client import ChatCompletionsClient


class ChatCompletionsStream:
    """Chat Completions protocol SSE parsing mixin.

    Provides shared implementation for streaming parsing (protocol level):
    - _parse_chunk_content(event_data) - Extract content from SSE event
    - _parse_chunk_usage(event_data) - Extract and normalize usage from SSE event
    - _parse_chunk_finish_reason(event_data) - Extract finish reason from SSE event
    - _build_stream_metadata(raw_events) - Filter content-only events

    Provider streams inherit this and override methods for provider-specific behavior
    (e.g., thinking model content parsing, non-standard usage locations).

    Modality streams call super() methods which resolve to this via MRO.
    """

    def _parse_chunk_content(self, event_data: dict[str, Any]) -> str | None:
        """Extract content from SSE event."""
        object_type = event_data.get("object")
        if object_type != "chat.completion.chunk":
            return None

        choices = event_data.get("choices", [])
        if not choices:
            return None

        first_choice = choices[0]
        if not isinstance(first_choice, dict):
            return None

        delta = first_choice.get("delta", {})
        if not isinstance(delta, dict):
            return None

        return delta.get("content") or None

    def _parse_chunk_usage(
        self, event_data: dict[str, Any]
    ) -> dict[str, int | float | None] | None:
        """Extract and normalize usage from SSE event."""
        usage_data = event_data.get("usage")
        if isinstance(usage_data, dict):
            return ChatCompletionsClient.map_usage_fields(usage_data)

        return None

    def _parse_chunk_finish_reason(
        self, event_data: dict[str, Any]
    ) -> FinishReason | None:
        """Extract finish reason from SSE event."""
        object_type = event_data.get("object")
        if object_type != "chat.completion.chunk":
            return None

        choices = event_data.get("choices", [])
        if not choices:
            return None

        first_choice = choices[0]
        if not isinstance(first_choice, dict):
            return None

        finish_reason = first_choice.get("finish_reason")
        if finish_reason:
            return FinishReason(reason=finish_reason)

        return None

    def _build_stream_metadata(
        self, raw_events: list[dict[str, Any]]
    ) -> dict[str, Any]:
        """Filter content-only events for size efficiency."""
        filtered = [event for event in raw_events if event.get("usage")]
        return super()._build_stream_metadata(filtered)  # type: ignore[misc, no-any-return]


__all__ = ["ChatCompletionsStream"]
