"""Tests for RiskOrchestrator (persistent sandwich loop)."""

from __future__ import annotations

import pytest

from pyfortis._types import (
    GateVerdict,
    Order,
    Position,
    Side,
)
from pyfortis.gate import RiskEngine
from pyfortis.stores.memory import InMemoryBreachStore, InMemoryPositionStore


@pytest.fixture
def orchestrator(sample_config):
    engine = RiskEngine.from_dict(sample_config)
    return engine.create_orchestrator()


class TestOrchestratorValidateOrder:
    def test_approve(self, orchestrator):
        order = Order(
            order_id="o-1", instrument="AAPL", side=Side.BUY,
            quantity=100, price=150.0,
        )
        result = orchestrator.validate_order(order)
        assert result.is_approved

    def test_reject_with_existing_position(self, orchestrator):
        orchestrator.on_position_update(
            Position(instrument="AAPL", quantity=9000, avg_price=150.0, current_price=150.0)
        )
        order = Order(
            order_id="o-2", instrument="AAPL", side=Side.BUY,
            quantity=2000, price=150.0,
        )
        result = orchestrator.validate_order(order)
        assert result.is_rejected


class TestOrchestratorMetrics:
    def test_run_metrics(self, orchestrator, sample_returns):
        orchestrator.on_position_update(
            Position(instrument="AAPL", quantity=100, avg_price=150.0, current_price=155.0)
        )
        results = orchestrator.run_metrics(returns_data=sample_returns)
        assert len(results) >= 1


class TestOrchestratorCircuitBreakers:
    def test_trip_and_halt(self, orchestrator):
        tripped = orchestrator.check_circuit_breakers(daily_pnl=-60000, current_value=900000)
        assert len(tripped) == 1
        assert orchestrator.is_halted

    def test_no_trip(self, orchestrator):
        tripped = orchestrator.check_circuit_breakers(daily_pnl=-10000, current_value=990000)
        assert len(tripped) == 0
        assert not orchestrator.is_halted


class TestOrchestratorPositionUpdate:
    def test_on_position_update(self, orchestrator):
        pos = Position(instrument="AAPL", quantity=100, avg_price=150.0, current_price=155.0)
        orchestrator.on_position_update(pos)
        monitor_pos = orchestrator.monitor.get_positions()
        assert "AAPL" in monitor_pos


class TestOrchestratorWithCustomStores:
    def test_custom_stores(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        pos_store = InMemoryPositionStore()
        breach_store = InMemoryBreachStore()

        orch = engine.create_orchestrator(
            position_store=pos_store,
            breach_store=breach_store,
        )

        # Add position via store
        pos = Position(instrument="AAPL", quantity=100, avg_price=150.0, current_price=155.0)
        pos_store.save_position(pos)

        # Validate — orchestrator loads from store
        order = Order(
            order_id="o-1", instrument="AAPL", side=Side.BUY,
            quantity=100, price=150.0,
        )
        result = orch.validate_order(order)
        assert result.is_approved

    def test_breaches_persisted(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        breach_store = InMemoryBreachStore()
        orch = engine.create_orchestrator(breach_store=breach_store)

        order = Order(
            order_id="o-bad", instrument="AAPL", side=Side.BUY,
            quantity=20000, price=150.0,
        )
        result = orch.validate_order(order)
        assert result.is_rejected

        breaches = breach_store.get_breaches()
        assert len(breaches) > 0
