"""Trigger evaluation and decision service.

Orchestrate trigger detection with rate limiting and snooze support.
"""

from __future__ import annotations

import time
from dataclasses import dataclass
from typing import TYPE_CHECKING

from noteflow.domain.triggers.entities import TriggerAction, TriggerDecision, TriggerSignal
from noteflow.infrastructure.logging import get_logger

if TYPE_CHECKING:
    from noteflow.domain.triggers.ports import SignalProvider

logger = get_logger(__name__)


@dataclass
class TriggerServiceSettings:
    """Configuration for trigger service.

    Attributes:
        enabled: Whether trigger detection is enabled.
        auto_start_enabled: Whether to auto-start recording at high confidence.
        rate_limit_seconds: Minimum seconds between trigger prompts.
        snooze_seconds: Default snooze duration.
        threshold_ignore: Confidence below which triggers are ignored.
        threshold_auto_start: Confidence at or above which auto-start is allowed.
    """

    enabled: bool
    auto_start_enabled: bool
    rate_limit_seconds: int
    snooze_seconds: int
    threshold_ignore: float
    threshold_auto_start: float

    def __post_init__(self) -> None:
        if self.threshold_auto_start < self.threshold_ignore:
            msg = "threshold_auto_start must be >= threshold_ignore"
            raise ValueError(msg)


class TriggerService:
    """Orchestrate trigger detection with rate limiting and snooze.

    Evaluates all signal providers and determines the appropriate action
    based on combined confidence scores, rate limits, and snooze state.

    Threshold behavior is driven by TriggerServiceSettings:
    - Confidence < threshold_ignore: IGNORE
    - Confidence >= threshold_auto_start: AUTO_START (if enabled, else NOTIFY)
    - Otherwise: NOTIFY
    """

    def __init__(
        self,
        providers: list[SignalProvider],
        settings: TriggerServiceSettings,
    ) -> None:
        """Initialize trigger service.

        Args:
            providers: List of signal providers to evaluate.
            settings: Configuration settings for trigger behavior.
        """
        self._providers = providers
        self._settings = settings
        self._last_prompt: float | None = None
        self._snoozed_until: float | None = None

    @property
    def is_enabled(self) -> bool:
        """Check if trigger service is enabled."""
        return self._settings.enabled

    @property
    def is_snoozed(self) -> bool:
        """Check if triggers are currently snoozed."""
        if self._snoozed_until is None:
            return False
        return time.monotonic() < self._snoozed_until

    @property
    def snooze_remaining_seconds(self) -> float:
        """Get remaining snooze time in seconds, or 0 if not snoozed."""
        if self._snoozed_until is None:
            return 0.0
        remaining = self._snoozed_until - time.monotonic()
        return max(0.0, remaining)

    def evaluate(self) -> TriggerDecision:
        """Evaluate all providers and determine action.

        Returns:
            TriggerDecision with action and confidence details.
        """
        now = time.monotonic()

        # Check if disabled
        if not self._settings.enabled:
            return self._make_decision(TriggerAction.IGNORE, 0.0, ())

        # Check if snoozed
        if self._snoozed_until is not None and now < self._snoozed_until:
            return self._make_decision(TriggerAction.IGNORE, 0.0, ())

        # Collect signals from all enabled providers
        signals: list[TriggerSignal] = []
        for provider in self._providers:
            if not provider.is_enabled():
                continue
            if signal := provider.get_signal():
                signals.append(signal)

        # Calculate total confidence
        confidence = sum(s.weight for s in signals)

        # Determine action
        action = self._determine_action(confidence, now)

        # Record prompt time for rate limiting
        if action in (TriggerAction.NOTIFY, TriggerAction.AUTO_START):
            self._last_prompt = now
            logger.info(
                "Trigger %s: confidence=%.2f, signals=%d",
                action.value,
                confidence,
                len(signals),
            )

        return self._make_decision(action, confidence, tuple(signals))

    def _determine_action(self, confidence: float, now: float) -> TriggerAction:
        """Determine action based on confidence and rate limits.

        Args:
            confidence: Total confidence from all signals.
            now: Current monotonic time.

        Returns:
            TriggerAction to take.
        """
        # Check threshold_ignore first
        if confidence < self._settings.threshold_ignore:
            return TriggerAction.IGNORE

        # AUTO_START bypasses rate limit (high-confidence trigger should not be delayed)
        if confidence >= self._settings.threshold_auto_start and self._settings.auto_start_enabled:
            return TriggerAction.AUTO_START

        # Rate limit applies only to NOTIFY actions
        if self._last_prompt is not None:
            elapsed = now - self._last_prompt
            if elapsed < self._settings.rate_limit_seconds:
                return TriggerAction.IGNORE

        return TriggerAction.NOTIFY

    def _make_decision(
        self,
        action: TriggerAction,
        confidence: float,
        signals: tuple[TriggerSignal, ...],
    ) -> TriggerDecision:
        """Create a TriggerDecision with the given parameters."""
        return TriggerDecision(
            action=action,
            confidence=confidence,
            signals=signals,
        )

    def snooze(self, seconds: int | None = None) -> None:
        """Snooze triggers for the specified duration.

        Args:
            seconds: Snooze duration in seconds (uses default if None).
        """
        duration = seconds if seconds is not None else self._settings.snooze_seconds
        self._snoozed_until = time.monotonic() + duration
        logger.info("Triggers snoozed for %d seconds", duration)

    def clear_snooze(self) -> None:
        """Clear any active snooze."""
        if self._snoozed_until is not None:
            self._snoozed_until = None
            logger.info("Trigger snooze cleared")

    def set_enabled(self, enabled: bool) -> None:
        """Enable or disable trigger detection.

        Args:
            enabled: Whether triggers should be enabled.
        """
        self._settings.enabled = enabled
        logger.info("Triggers %s", "enabled" if enabled else "disabled")

    def set_auto_start(self, enabled: bool) -> None:
        """Enable or disable auto-start on high confidence.

        Args:
            enabled: Whether auto-start should be enabled.
        """
        self._settings.auto_start_enabled = enabled
        logger.info("Auto-start %s", "enabled" if enabled else "disabled")
