"""Retry logic and circuit breaker for upstream provider failures."""

from __future__ import annotations

import logging
import time
from collections import defaultdict
from dataclasses import dataclass, field

logger = logging.getLogger("ecate.proxy.fallback")

_CIRCUIT_WINDOW = 300  # 5 minutes
_CIRCUIT_HALF_OPEN_AFTER = 60  # seconds


@dataclass
class CircuitState:
    failures: list[float] = field(default_factory=list)
    opened_at: float | None = None

    def record_failure(self):
        now = time.time()
        self.failures = [t for t in self.failures if now - t < _CIRCUIT_WINDOW]
        self.failures.append(now)

    def record_success(self):
        self.failures.clear()
        self.opened_at = None

    def is_open(self, threshold: int) -> bool:
        now = time.time()
        recent = [t for t in self.failures if now - t < _CIRCUIT_WINDOW]
        if len(recent) >= threshold:
            if self.opened_at is None:
                self.opened_at = now
            # Allow half-open attempt after cooldown
            if now - self.opened_at > _CIRCUIT_HALF_OPEN_AFTER:
                return False
            return True
        return False


class CircuitBreaker:
    """Per-model circuit breaker to temporarily remove failing models from routing."""

    def __init__(self, threshold: int = 3):
        self._threshold = threshold
        self._circuits: dict[str, CircuitState] = defaultdict(CircuitState)

    def is_available(self, model_id: str) -> bool:
        return not self._circuits[model_id].is_open(self._threshold)

    def record_success(self, model_id: str):
        self._circuits[model_id].record_success()

    def record_failure(self, model_id: str):
        self._circuits[model_id].record_failure()
        if self._circuits[model_id].is_open(self._threshold):
            logger.warning(f"Circuit breaker OPEN for {model_id}")

    def get_status(self) -> dict[str, str]:
        return {
            model_id: "open" if state.is_open(self._threshold) else "closed"
            for model_id, state in self._circuits.items()
        }
