"""RiskOrchestrator — persistent sandwich loop (Layer 3)."""

from __future__ import annotations

import logging
from typing import Any

from pyfortis._engine import Engine
from pyfortis._types import (
    BreachAction,
    BreachRecord,
    CircuitBreakerSpec,
    Exposure,
    GateResult,
    MetricResult,
    Order,
    Position,
    Severity,
)
from pyfortis.handlers import HandlerExecutor, HandlerRegistry
from pyfortis.monitor import RiskMonitor
from pyfortis.stores.base import BreachStore, PositionStore

logger = logging.getLogger(__name__)


class RiskOrchestrator:
    """Persistent sandwich loop: load → evaluate → persist → alert.

    Analogous to pystator's ``Orchestrator``.
    """

    def __init__(
        self,
        engine: Engine,
        handler_registry: HandlerRegistry,
        position_store: PositionStore,
        breach_store: BreachStore,
    ) -> None:
        self._engine = engine
        self._handler_executor = HandlerExecutor(handler_registry)
        self._position_store = position_store
        self._breach_store = breach_store
        self._monitor = RiskMonitor(engine, handler_registry)

    # ── Pre-trade gate ─────────────────────────────────────────────────

    def validate_order(
        self,
        order: Order,
        context: dict[str, Any] | None = None,
    ) -> GateResult:
        """Sandwich: load positions → evaluate → persist breaches → handle."""
        # Load
        positions = self._position_store.get_positions(order.portfolio)

        # Update monitor with fresh positions
        self._monitor.update_positions(list(positions.values()))

        # Evaluate
        result = self._monitor.validate_order(order, context)

        # Persist breaches
        if result.breaches:
            self._breach_store.save_breaches(result.breaches)

        return result

    # ── Post-trade metrics ─────────────────────────────────────────────

    def run_metrics(
        self,
        portfolio: str = "default",
        returns_data: list[float] | None = None,
        context: dict[str, Any] | None = None,
    ) -> list[MetricResult]:
        """Load positions → compute metrics → persist metric breaches."""
        # Load
        positions = self._position_store.get_positions(portfolio)
        self._monitor.update_positions(list(positions.values()))

        # Compute
        results = self._monitor.compute_metrics(returns_data, context)

        # Persist breached metrics
        breaches = []
        for r in results:
            if r.breach and r.severity is not None:
                breaches.append(
                    BreachRecord(
                        limit_name=r.metric_name,
                        severity=r.severity,
                        message=r.message,
                        actions=[BreachAction.LOG, BreachAction.NOTIFY],
                        details=r.details,
                    )
                )

        if breaches:
            self._breach_store.save_breaches(breaches)
            self._handler_executor.execute_all(breaches, context)

        return results

    # ── Circuit breakers ───────────────────────────────────────────────

    def check_circuit_breakers(
        self,
        daily_pnl: float = 0.0,
        current_value: float = 0.0,
        volatility: float = 0.0,
    ) -> list[CircuitBreakerSpec]:
        """Evaluate circuit breakers → persist → handle."""
        self._monitor.update_pnl(daily_pnl, current_value)
        tripped = self._monitor.check_circuit_breakers()

        if tripped:
            breaches = []
            for cb in tripped:
                breach = BreachRecord(
                    limit_name=cb.name,
                    severity=Severity.KILL,
                    message=f"Circuit breaker '{cb.name}' tripped",
                    actions=[cb.action],
                    details=dict(cb.params),
                )
                breaches.append(breach)

            self._breach_store.save_breaches(breaches)
            self._handler_executor.execute_all(breaches)

        return tripped

    # ── Position updates ───────────────────────────────────────────────

    def on_position_update(self, position: Position) -> None:
        """Persist position and update monitor."""
        self._position_store.save_position(position)
        self._monitor.update_position(position)

    # ── State queries ──────────────────────────────────────────────────

    @property
    def monitor(self) -> RiskMonitor:
        return self._monitor

    @property
    def is_halted(self) -> bool:
        return self._monitor.is_halted
