from __future__ import annotations

from collections import deque
from dataclasses import dataclass, field
from typing import Any, Optional


@dataclass(slots=True)
class PendingUserTurn:
    seq: int
    transcription: str
    text: str
    message_id: str = ""


@dataclass(slots=True)
class DeferredVADUtterance:
    """A fala encerrada pelo VAD, aguardando seu STT final correspondente."""

    duration_ms: int
    is_long: bool
    ended_at: float = 0.0


@dataclass(slots=True)
class DeferredInterruptionState:
    # Janela do ciclo: aberta enquanto o backend do turno original esta em voo,
    # fechada assim que a resposta dele e liberada para o playout. Fora dela a
    # fala do cliente e uma interrupcao comum e segue o fluxo normal.
    backend_in_flight: bool = False
    # Finais VAD anteriores a R1 cujo STT ainda nao terminou.
    pre_backend_vad_utterances: deque[DeferredVADUtterance] = field(default_factory=deque)
    pending_vad_utterances: deque[DeferredVADUtterance] = field(default_factory=deque)
    pending_long_stt_finals: int = 0
    long_turns: list[PendingUserTurn] = field(default_factory=list)
    special_comfort_sent: bool = False
    replay_in_flight: bool = False
    # Incrementado a cada reset para que uma tarefa de conforto atrasada nao
    # toque no ciclo seguinte.
    cycle_seq: int = 0


@dataclass(slots=True)
class GapState:
    active: bool = False
    guard_seq: int = 0
    stage: str = ""
    text: str = ""
    speech_id: str = ""
    cancelled: bool = False


@dataclass(slots=True)
class CurrentSpeechState:
    handle: Optional[Any] = None
    stage: str = ""
    text: str = ""
    speech_id: str = ""
    allow_interruptions: bool = False
    rearm_interruptions_on_next_user_speech: bool = False
    drop_user_input_while_speaking: bool = False
    agent_message_type: str = ""
    agent_result_type: str = ""
    interruption_requested: bool = False
    interruption_task: Optional[Any] = None

@dataclass(slots=True)
class CallState:
    current_stage: str = "INTRO"
    pending_user_final: Optional[PendingUserTurn] = None
    user_final_seq: int = 0
    last_user_final_at: float = 0.0
    idle_nudge_count: int = 0
    gap: GapState = field(default_factory=GapState)
    current_speech: CurrentSpeechState = field(default_factory=CurrentSpeechState)
    deferred_interruption: DeferredInterruptionState = field(default_factory=DeferredInterruptionState)


@dataclass(frozen=True, slots=True)
class RuntimeConfig:
    call_end_grace_s: float
    final_grace_s: float
    idle_nudge_delay_s: float
    idle_nudge_join_delay_s: float
    idle_nudge_close_delay_s: float
    idle_nudge_max_tries: int
    idle_nudge_end_reason: str
    inflight_backend_wait_interval_s: float = 0.0
    inflight_backend_wait_timeout_s: float = 0.0
    inflight_backend_wait_max_notices: int = 0
    inflight_backend_wait_text: str = ""
    inflight_backend_wait_short_audio_dir: str = ""
    inflight_backend_wait_long_audio_dir: str = ""
    inflight_backend_wait_long_audio_path: str = ""
    pre_backend_wait_notice_fast_on_vad_pause: bool = False
    deferred_interruption_enabled: bool = True
    deferred_interruption_min_audio_ms: int = 1000
    deferred_interruption_stt_settle_timeout_s: float = 3.0
    deferred_interruption_user_turn_timeout_s: float = 10.0
