"""Tests for RiskEngine (gate.py)."""

from __future__ import annotations

import pytest

from pyfortis._types import (
    GateVerdict,
    LimitCheckResult,
    Order,
    Position,
    Severity,
    Side,
)
from pyfortis.gate import RiskEngine


class TestRiskEngineFromDict:
    def test_from_dict(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        assert len(engine.limits) == 2
        assert len(engine.metrics) == 1
        assert len(engine.circuit_breakers) == 1

    def test_repr(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        r = repr(engine)
        assert "test_engine" in r
        assert "limits=2" in r

    def test_builtins_registered(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        assert "position" in engine.validator_names
        assert "concentration" in engine.validator_names
        assert "var" in engine.calculator_names
        assert "log" in engine.handler_names


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

    def test_reject_position_breach(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        order = Order(
            order_id="o-2", instrument="AAPL", side=Side.BUY,
            quantity=20000, price=150.0,
        )
        result = engine.validate_order(order)
        assert result.is_rejected

    def test_with_positions(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        positions = {
            "AAPL": Position(
                instrument="AAPL", quantity=9000,
                avg_price=150.0, current_price=150.0,
            ),
        }
        order = Order(
            order_id="o-3", instrument="AAPL", side=Side.BUY,
            quantity=2000, price=150.0,
        )
        result = engine.validate_order(order, positions=positions)
        assert result.is_rejected  # 9000 + 2000 = 11000 > 10000


class TestRiskEngineDecorators:
    def test_custom_validator(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)

        @engine.validator("custom_check")
        def custom_check(limit, order, positions, exposures, context):
            return LimitCheckResult(
                limit_name=limit.name,
                passed=True,
                severity=Severity.INFO,
                message="Custom passed",
            )

        assert "custom_check" in engine.validator_names

    def test_custom_handler(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        calls = []

        @engine.handler("notify")
        def notify(breach, ctx):
            calls.append(breach.limit_name)

        assert "notify" in engine.handler_names


class TestRiskEngineComputeMetrics:
    def test_compute_metrics(self, sample_config, sample_returns):
        engine = RiskEngine.from_dict(sample_config)
        results = engine.compute_metrics(returns_data=sample_returns)
        assert len(results) == 1  # Only var metric in sample_config
        assert results[0].metric_name == "portfolio_var"


class TestRiskEngineCircuitBreakers:
    def test_no_trip(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        tripped = engine.evaluate_circuit_breakers(daily_pnl=-10000)
        assert len(tripped) == 0

    def test_trip(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        tripped = engine.evaluate_circuit_breakers(daily_pnl=-60000)
        assert len(tripped) == 1


class TestRiskEngineCreateMonitor:
    def test_create_monitor(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        monitor = engine.create_monitor()
        assert monitor is not None
        assert not monitor.is_halted


class TestRiskEngineCreateOrchestrator:
    def test_create_orchestrator(self, sample_config):
        engine = RiskEngine.from_dict(sample_config)
        orch = engine.create_orchestrator()
        assert orch is not None
        assert not orch.is_halted
