from __future__ import annotations

from dataclasses import dataclass
from typing import Optional


@dataclass(frozen=True, slots=True)
class IdlePolicyConfig:
    enabled: bool
    delay_s: float
    join_delay_s: float
    close_delay_s: float
    max_tries: int
    end_reason: str


class IdlePolicy:
    def __init__(self, config: IdlePolicyConfig) -> None:
        self._config = config

    @property
    def close_delay_s(self) -> float:
        return self._config.close_delay_s

    @property
    def max_tries(self) -> int:
        return self._config.max_tries

    @property
    def end_reason(self) -> str:
        return self._config.end_reason or "no_user_response"

    @property
    def enabled(self) -> bool:
        return bool(self._config.enabled)

    @property
    def join_delay_s(self) -> float:
        return self._config.join_delay_s

    def resolve_delay(self, delay_s: Optional[float] = None) -> float:
        return self._config.delay_s if delay_s is None else float(delay_s)

    def should_arm_nudge(self, *, delay_s: float, nudge_text: str) -> bool:
        if not self.enabled:
            return False
        if delay_s <= 0:
            return False
        if not nudge_text:
            return False
        if self._config.max_tries <= 0:
            return False
        return True

    def should_fire_nudge(
        self,
        *,
        token_is_current: bool,
        seq_matches: bool,
        speaking: bool,
        gap_active: bool,
        finalized: bool,
        current_stage: str,
    ) -> bool:
        if not self.enabled:
            return False
        if not token_is_current:
            return False
        if not seq_matches:
            return False
        if speaking or gap_active:
            return False
        if finalized:
            return False
        if (current_stage or "").upper() == "DONE":
            return False
        return True

    def should_arm_close_before_fire(self, *, nudge_count: int) -> bool:
        if not self.enabled:
            return False
        return nudge_count >= self._config.max_tries

    def should_fire_close(
        self,
        *,
        token_is_current: bool,
        seq_matches: bool,
        finalized: bool,
        current_stage: str,
    ) -> bool:
        if not self.enabled:
            return False
        if not token_is_current:
            return False
        if not seq_matches:
            return False
        if finalized:
            return False
        if (current_stage or "").upper() == "DONE":
            return False
        return True

    def should_arm_close_after_nudge(self, *, stage: str, nudge_count: int) -> bool:
        if not self.enabled:
            return False
        return (stage or "").upper() == "IDLE_NUDGE" and nudge_count >= self._config.max_tries
