"""Tests for the operator approval workflow for live trading mode.

Validates:
- requires_approval logic for paper/live/disabled modes
- ApprovalRequest model behavior (pending, expired)
- compute_expiry calculation
- Integration with broker service process_order_job flow
"""
from datetime import datetime, timedelta, timezone

from services.risk.approval import (
    ApprovalRequest,
    ApprovalStatus,
    compute_expiry,
    requires_approval,
)
from services.risk.engine import (
    OperatorApproval,
    PortfolioRiskConfig,
    TradingMode,
)

# ---------------------------------------------------------------------------
# requires_approval tests
# ---------------------------------------------------------------------------


class TestRequiresApproval:
    def test_paper_mode_auto_approved(self):
        """Paper orders are auto-approved by default."""
        config = PortfolioRiskConfig(trading_mode=TradingMode.PAPER)
        assert requires_approval(config) is False

    def test_paper_mode_approval_required_when_auto_approve_off(self):
        """Paper orders need approval when auto_approve_paper is False."""
        config = PortfolioRiskConfig(
            trading_mode=TradingMode.PAPER,
            operator_approval=OperatorApproval(auto_approve_paper=False),
        )
        assert requires_approval(config) is True

    def test_live_mode_requires_approval_by_default(self):
        """Live orders require approval by default."""
        config = PortfolioRiskConfig(trading_mode=TradingMode.LIVE)
        assert requires_approval(config) is True

    def test_live_mode_no_approval_when_disabled(self):
        """Live orders skip approval when require_approval_for_live is False."""
        config = PortfolioRiskConfig(
            trading_mode=TradingMode.LIVE,
            operator_approval=OperatorApproval(require_approval_for_live=False),
        )
        assert requires_approval(config) is False

    def test_disabled_mode_never_requires_approval(self):
        """Disabled mode never requires approval (blocked upstream)."""
        config = PortfolioRiskConfig(trading_mode=TradingMode.DISABLED)
        assert requires_approval(config) is False

    def test_override_trading_mode_parameter(self):
        """The trading_mode parameter overrides config.trading_mode."""
        config = PortfolioRiskConfig(trading_mode=TradingMode.PAPER)
        # Override to live — should require approval
        assert requires_approval(config, trading_mode=TradingMode.LIVE) is True


# ---------------------------------------------------------------------------
# compute_expiry tests
# ---------------------------------------------------------------------------


class TestComputeExpiry:
    def test_default_30_minutes(self):
        now = datetime(2026, 4, 11, 12, 0, 0, tzinfo=timezone.utc)
        config = PortfolioRiskConfig()
        expiry = compute_expiry(config, now=now)
        assert expiry == now + timedelta(minutes=30)

    def test_custom_timeout(self):
        now = datetime(2026, 4, 11, 12, 0, 0, tzinfo=timezone.utc)
        config = PortfolioRiskConfig(
            operator_approval=OperatorApproval(approval_timeout_minutes=60),
        )
        expiry = compute_expiry(config, now=now)
        assert expiry == now + timedelta(minutes=60)


# ---------------------------------------------------------------------------
# ApprovalRequest model tests
# ---------------------------------------------------------------------------


class TestApprovalRequest:
    def test_defaults(self):
        req = ApprovalRequest(ticker="AAPL")
        assert req.ticker == "AAPL"
        assert req.status == ApprovalStatus.PENDING
        assert req.is_pending is True
        assert req.approval_id  # auto-generated UUID

    def test_is_expired_when_past_expiry(self):
        past = datetime.now(timezone.utc) - timedelta(minutes=5)
        req = ApprovalRequest(ticker="AAPL", expires_at=past)
        assert req.is_expired is True

    def test_not_expired_when_future_expiry(self):
        future = datetime.now(timezone.utc) + timedelta(minutes=30)
        req = ApprovalRequest(ticker="AAPL", expires_at=future)
        assert req.is_expired is False

    def test_approved_is_not_expired(self):
        past = datetime.now(timezone.utc) - timedelta(minutes=5)
        req = ApprovalRequest(
            ticker="AAPL",
            status=ApprovalStatus.APPROVED,
            expires_at=past,
        )
        assert req.is_expired is False

    def test_to_dict_roundtrip(self):
        req = ApprovalRequest(
            ticker="MSFT",
            side="sell",
            quantity=50.0,
            estimated_value=15000.0,
            recommendation_id="rec-123",
        )
        d = req.to_dict()
        assert d["ticker"] == "MSFT"
        assert d["side"] == "sell"
        assert d["quantity"] == 50.0
        assert d["status"] == "pending"
        assert d["recommendation_id"] == "rec-123"

    def test_explicit_expired_status(self):
        req = ApprovalRequest(
            ticker="AAPL",
            status=ApprovalStatus.EXPIRED,
        )
        assert req.is_expired is True
        assert req.is_pending is False
