"""Financial Circuit Breakers & Loss Guardrails."""
from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal
from typing import Optional

from backend.app.config.settings import settings
from backend.app.schemas.risk import AccountState


@dataclass
class CircuitBreakerStatus:
    tripped: bool
    reason: Optional[str] = None


class CircuitBreakerManager:
    """Evaluates macro portfolio health, intraday loss bounds, and peak drawdowns."""

    def __init__(
        self,
        max_daily_loss_pct: Optional[float] = None,
        max_drawdown_pct: Optional[float] = None,
        max_positions: Optional[int] = None,
    ) -> None:
        self.max_daily_loss_pct = Decimal(str(max_daily_loss_pct if max_daily_loss_pct is not None else settings.MAX_DAILY_LOSS_PCT))
        self.max_drawdown_pct = Decimal(str(max_drawdown_pct if max_drawdown_pct is not None else settings.MAX_DRAWDOWN_PCT))
        self.max_positions = max_positions if max_positions is not None else settings.MAX_POSITIONS

    def check_portfolio_limits(self, account: AccountState) -> CircuitBreakerStatus:
        # 1. Open positions count
        if account.open_positions_count >= self.max_positions:
            return CircuitBreakerStatus(
                tripped=True,
                reason=f"Maximum simultaneous positions limit reached ({account.open_positions_count}/{self.max_positions}).",
            )

        # 2. Daily loss limit check
        if account.starting_day_equity > Decimal("0"):
            total_daily_pnl = account.realized_daily_pnl + account.unrealized_daily_pnl
            daily_loss_ratio = -total_daily_pnl / account.starting_day_equity
            if daily_loss_ratio >= self.max_daily_loss_pct:
                return CircuitBreakerStatus(
                    tripped=True,
                    reason=(
                        f"Daily loss circuit breaker tripped: current loss {daily_loss_ratio*100:.2f}% "
                        f"exceeds daily maximum limit of {self.max_daily_loss_pct*100:.2f}%."
                    ),
                )

        # 3. Overall drawdown from peak check
        if account.peak_equity > Decimal("0"):
            drawdown = (account.peak_equity - account.equity) / account.peak_equity
            if drawdown >= self.max_drawdown_pct:
                return CircuitBreakerStatus(
                    tripped=True,
                    reason=(
                        f"Maximum drawdown circuit breaker tripped: drawdown {drawdown*100:.2f}% "
                        f"exceeds portfolio risk tolerance limit of {self.max_drawdown_pct*100:.2f}%."
                    ),
                )

        return CircuitBreakerStatus(tripped=False)


circuit_breakers = CircuitBreakerManager()
