"""Deepgram streaming types for real-time STT.

Pydantic v2 models for Deepgram WebSocket API responses.
These are standalone types - no dependency on Deepgram SDK.
"""

from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, Field, ConfigDict


# =============================================================================
# Configuration
# =============================================================================


class DeepgramConfig(BaseModel):
    """Configuration for Deepgram streaming connection.

    Immutable configuration object for WebSocket connection parameters.

    Example:
        ```python
        config = DeepgramConfig(
            model="nova-3",
            language="en-US",
            sample_rate=16000,
            diarize=True,
        )
        ```
    """

    model_config = ConfigDict(frozen=True)

    # Model settings
    model: str = Field(default="nova-3", description="Deepgram model: nova-3, nova-2, enhanced, base")
    language: str = Field(default="en-US", description="Language code (e.g., en-US, es, ja)")

    # Audio format
    sample_rate: int = Field(default=16000, ge=8000, le=48000, description="Audio sample rate in Hz")
    channels: int = Field(default=1, ge=1, le=2, description="Number of audio channels")
    encoding: str = Field(default="linear16", description="Audio encoding: linear16, flac, mulaw, opus")

    # Features
    punctuate: bool = Field(default=True, description="Add punctuation")
    smart_format: bool = Field(default=False, description="Smart formatting (numbers, dates)")
    diarize: bool = Field(default=False, description="Speaker diarization")
    utterances: bool = Field(default=False, description="Detect utterance boundaries")

    # Streaming
    interim_results: bool = Field(default=True, description="Return interim (non-final) results")
    endpointing: int = Field(default=300, ge=0, le=5000, description="Silence detection threshold (ms)")
    vad_events: bool = Field(default=True, description="Voice activity detection events")

    # Keywords
    keywords: list[str] = Field(default_factory=list, description="Boost recognition of these words")


# =============================================================================
# WebSocket Message Types
# =============================================================================


DeepgramMessageType = Literal[
    "Results",       # Transcription results
    "Metadata",      # Session metadata
    "UtteranceEnd",  # End of utterance
    "SpeechStarted", # Speech detected
    "Error",         # Error message
]


class DeepgramWord(BaseModel):
    """Single word with timing information."""

    word: str = Field(description="The transcribed word")
    start: float = Field(description="Start time in seconds")
    end: float = Field(description="End time in seconds")
    confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Word confidence")
    speaker: int | None = Field(default=None, description="Speaker ID (if diarization enabled)")
    punctuated_word: str | None = Field(default=None, description="Word with punctuation")


class DeepgramAlternative(BaseModel):
    """Single transcription alternative."""

    transcript: str = Field(description="Transcribed text")
    confidence: float = Field(default=0.0, ge=0.0, le=1.0, description="Overall confidence")
    words: list[DeepgramWord] = Field(default_factory=list, description="Word-level details")


class DeepgramChannel(BaseModel):
    """Channel transcription data."""

    alternatives: list[DeepgramAlternative] = Field(default_factory=list)


class DeepgramResults(BaseModel):
    """Transcription results message from Deepgram.

    Received when audio is transcribed. Contains interim or final results.

    Example response:
        ```json
        {
            "type": "Results",
            "is_final": true,
            "speech_final": true,
            "channel": {"alternatives": [{"transcript": "hello world", "confidence": 0.98}]},
            "start": 0.0,
            "duration": 1.5
        }
        ```
    """

    type: Literal["Results"] = "Results"
    is_final: bool = Field(default=False, description="True if this is a final result")
    speech_final: bool = Field(default=False, description="True if end of speech detected")
    channel: DeepgramChannel = Field(default_factory=DeepgramChannel)
    start: float = Field(default=0.0, description="Start time in seconds")
    duration: float = Field(default=0.0, description="Duration in seconds")

    # Extra metadata
    channel_index: list[int] = Field(default_factory=lambda: [0, 1])
    from_finalize: bool = Field(default=False, description="Result from finalize request")

    @property
    def text(self) -> str:
        """Get the best transcript text."""
        if self.channel.alternatives:
            return self.channel.alternatives[0].transcript
        return ""

    @property
    def confidence(self) -> float:
        """Get the best confidence score."""
        if self.channel.alternatives:
            return self.channel.alternatives[0].confidence
        return 0.0

    @property
    def words(self) -> list[DeepgramWord]:
        """Get words from best alternative."""
        if self.channel.alternatives:
            return self.channel.alternatives[0].words
        return []


class DeepgramMetadata(BaseModel):
    """Session metadata from Deepgram.

    Received at the start of a streaming session.
    """

    type: Literal["Metadata"] = "Metadata"
    request_id: str = Field(description="Unique request identifier")
    model_uuid: str = Field(default="", description="Model UUID")
    model_info: dict = Field(default_factory=dict, description="Model information")
    sha256: str = Field(default="", description="Audio checksum")

    # Extra
    transaction_key: str = Field(default="", description="Transaction key")
    created: str = Field(default="", description="Created timestamp")
    duration: float = Field(default=0.0, description="Total audio duration")
    channels: int = Field(default=1, description="Number of channels")


class DeepgramUtteranceEnd(BaseModel):
    """Utterance end marker.

    Received when an utterance boundary is detected.
    """

    type: Literal["UtteranceEnd"] = "UtteranceEnd"
    channel: list[int] = Field(default_factory=lambda: [0, 1])
    last_word_end: float = Field(default=0.0, description="End time of last word")


class DeepgramSpeechStarted(BaseModel):
    """Speech started event.

    Received when voice activity is detected.
    """

    type: Literal["SpeechStarted"] = "SpeechStarted"
    channel: list[int] = Field(default_factory=lambda: [0, 1])
    timestamp: float = Field(default=0.0, description="Timestamp in seconds")


class DeepgramError(BaseModel):
    """Error message from Deepgram.

    Received when an error occurs during streaming.
    """

    type: Literal["Error"] = "Error"
    description: str = Field(description="Error description")
    message: str = Field(default="", description="Error message")
    variant: str = Field(default="", description="Error variant")
    err_code: str = Field(default="", description="Error code")


# =============================================================================
# Unified Transcript Segment (for client consumption)
# =============================================================================


class TranscriptWord(BaseModel):
    """Word with timing for client consumption.

    Simplified word model for SDK users.
    """

    word: str
    start_time: float = 0.0
    end_time: float = 0.0
    confidence: float = Field(default=0.9, ge=0.0, le=1.0)
    speaker_id: int | None = None


class TranscriptSegment(BaseModel):
    """Transcript segment for client consumption.

    Unified model that works across providers (Deepgram, Whisper, etc.).

    Example:
        ```python
        async for segment in client.deepgram.stream(audio_source):
            if segment.is_final:
                print(f"Final: {segment.text}")
            else:
                print(f"Interim: {segment.text}")
        ```
    """

    sequence: int = Field(description="Sequence number")
    text: str = Field(description="Transcribed text")
    is_final: bool = Field(default=False, description="True if final result")
    confidence: float = Field(default=0.9, ge=0.0, le=1.0)
    start_time: float = 0.0
    end_time: float = 0.0
    words: list[TranscriptWord] = Field(default_factory=list)

    # Extra metadata
    provider: str = Field(default="deepgram", description="Provider name")
    speech_final: bool = Field(default=False, description="End of speech detected")


# =============================================================================
# Streaming Events
# =============================================================================


class StreamReady(BaseModel):
    """Stream ready event sent to client after connection."""

    type: Literal["ready"] = "ready"
    session_id: str
    model: str
    sample_rate: int


class StreamDone(BaseModel):
    """Stream done event sent when session ends."""

    type: Literal["done"] = "done"
    duration: float = Field(description="Total audio duration in seconds")
    segments_count: int = Field(default=0, description="Number of final segments")


class StreamError(BaseModel):
    """Stream error event."""

    type: Literal["error"] = "error"
    message: str
    code: str = "unknown"
    details: dict = Field(default_factory=dict)


__all__ = [
    # Configuration
    "DeepgramConfig",
    # Message types
    "DeepgramMessageType",
    "DeepgramWord",
    "DeepgramAlternative",
    "DeepgramChannel",
    "DeepgramResults",
    "DeepgramMetadata",
    "DeepgramUtteranceEnd",
    "DeepgramSpeechStarted",
    "DeepgramError",
    # Client types
    "TranscriptWord",
    "TranscriptSegment",
    # Stream events
    "StreamReady",
    "StreamDone",
    "StreamError",
]
