"""Tests for live trading mode functionality.

This module contains tests for LiveModeConfig, LiveModeManager,
and trade limit validations.
"""

import pytest
from pydantic import ValidationError

from openclaw.trading.live_mode import (
    LiveModeConfig,
    LiveModeManager,
    LiveTradeLogEntry,
    TradingMode,
)


class TestLiveModeConfig:
    """Tests for LiveModeConfig Pydantic model."""

    def test_default_config_creation(self):
        """Test creating LiveModeConfig with default values."""
        config = LiveModeConfig()

        assert config.enabled is False
        assert config.daily_trade_limit_usd == 10000.0
        assert config.max_position_pct == 0.2
        assert config.require_confirmation is True
        assert config.confirmation_timeout_seconds == 30
        assert config.audit_log_path == "logs/live_trades.jsonl"
        assert config.alert_webhook_url is None

    def test_custom_config_creation(self):
        """Test creating LiveModeConfig with custom values."""
        config = LiveModeConfig(
            enabled=True,
            daily_trade_limit_usd=50000.0,
            max_position_pct=0.5,
            require_confirmation=False,
            confirmation_timeout_seconds=60,
            audit_log_path="logs/custom_trades.jsonl",
            alert_webhook_url="https://hooks.example.com/alerts",
        )

        assert config.enabled is True
        assert config.daily_trade_limit_usd == 50000.0
        assert config.max_position_pct == 0.5
        assert config.require_confirmation is False
        assert config.confirmation_timeout_seconds == 60
        assert config.audit_log_path == "logs/custom_trades.jsonl"
        assert config.alert_webhook_url == "https://hooks.example.com/alerts"

    def test_daily_trade_limit_validation(self):
        """Test daily_trade_limit_usd must be positive."""
        with pytest.raises(ValidationError):
            LiveModeConfig(daily_trade_limit_usd=0)

        with pytest.raises(ValidationError):
            LiveModeConfig(daily_trade_limit_usd=-1000.0)

    def test_max_position_pct_validation(self):
        """Test max_position_pct must be between 0 and 1."""
        with pytest.raises(ValidationError):
            LiveModeConfig(max_position_pct=0)

        with pytest.raises(ValidationError):
            LiveModeConfig(max_position_pct=1.5)

        with pytest.raises(ValidationError):
            LiveModeConfig(max_position_pct=-0.1)

    def test_confirmation_timeout_validation(self):
        """Test confirmation_timeout_seconds bounds."""
        with pytest.raises(ValidationError):
            LiveModeConfig(confirmation_timeout_seconds=4)

        with pytest.raises(ValidationError):
            LiveModeConfig(confirmation_timeout_seconds=301)

    def test_webhook_url_validation(self):
        """Test webhook URL must be valid HTTP/HTTPS."""
        # Valid URLs
        config1 = LiveModeConfig(alert_webhook_url="https://example.com/hook")
        assert config1.alert_webhook_url == "https://example.com/hook"

        config2 = LiveModeConfig(alert_webhook_url="http://example.com/hook")
        assert config2.alert_webhook_url == "http://example.com/hook"

        # Invalid URL
        with pytest.raises(ValidationError):
            LiveModeConfig(alert_webhook_url="ftp://example.com/hook")

        with pytest.raises(ValidationError):
            LiveModeConfig(alert_webhook_url="not_a_url")


class TestLiveModeManager:
    """Tests for LiveModeManager class."""

    def test_manager_initialization_default(self):
        """Test LiveModeManager initialization with default config."""
        manager = LiveModeManager()

        assert manager.is_live_mode is False
        assert manager.is_simulated_mode is True
        assert manager.config.enabled is False

    def test_manager_initialization_live(self):
        """Test LiveModeManager initialization in live mode."""
        config = LiveModeConfig(enabled=True)
        manager = LiveModeManager(config=config)

        assert manager.is_live_mode is True
        assert manager.is_simulated_mode is False

    def test_mode_indicator(self):
        """Test mode indicator string."""
        config_sim = LiveModeConfig(enabled=False)
        manager_sim = LiveModeManager(config=config_sim)
        assert "SIMULATED" in manager_sim.mode_indicator

        config_live = LiveModeConfig(enabled=True)
        manager_live = LiveModeManager(config=config_live)
        assert "LIVE" in manager_live.mode_indicator

    def test_get_daily_limit(self):
        """Test getting daily trade limit."""
        config = LiveModeConfig(daily_trade_limit_usd=25000.0)
        manager = LiveModeManager(config=config)

        assert manager.get_daily_limit() == 25000.0

    def test_get_daily_limit_remaining_initial(self):
        """Test remaining limit at initialization."""
        config = LiveModeConfig(enabled=True, daily_trade_limit_usd=10000.0)
        manager = LiveModeManager(config=config)

        assert manager.get_daily_limit_remaining() == 10000.0

    def test_validate_live_trade_not_in_live_mode(self):
        """Test trade validation fails when not in live mode."""
        config = LiveModeConfig(enabled=False)
        manager = LiveModeManager(config=config)

        is_valid, reason = manager.validate_live_trade(
            symbol="AAPL",
            amount=10.0,
            price=150.0,
            current_balance=10000.0,
        )

        assert is_valid is False
        assert "Not in live trading mode" in reason

    def test_validate_live_trade_exceeds_daily_limit(self):
        """Test trade validation fails when exceeding daily limit."""
        config = LiveModeConfig(enabled=True, daily_trade_limit_usd=1000.0)
        manager = LiveModeManager(config=config)

        is_valid, reason = manager.validate_live_trade(
            symbol="AAPL",
            amount=10.0,
            price=200.0,  # $2000 trade value
            current_balance=10000.0,
        )

        assert is_valid is False
        assert "Daily limit exceeded" in reason

    def test_validate_live_trade_exceeds_position_limit(self):
        """Test trade validation fails when exceeding position size limit."""
        config = LiveModeConfig(
            enabled=True,
            daily_trade_limit_usd=100000.0,
            max_position_pct=0.1,  # 10% max position
        )
        manager = LiveModeManager(config=config)

        is_valid, reason = manager.validate_live_trade(
            symbol="AAPL",
            amount=100.0,
            price=200.0,  # $20000 position
            current_balance=10000.0,  # max_position = $1000
        )

        assert is_valid is False
        assert "Position size exceeds limit" in reason

    def test_validate_live_trade_insufficient_balance(self):
        """Test trade validation fails with insufficient balance."""
        config = LiveModeConfig(
            enabled=True,
            daily_trade_limit_usd=100000.0,
            max_position_pct=1.0,
        )
        manager = LiveModeManager(config=config)

        is_valid, reason = manager.validate_live_trade(
            symbol="AAPL",
            amount=1.0,
            price=1000.0,
            current_balance=1000.0,  # Required with 1.5x buffer = $1500
        )

        assert is_valid is False
        assert "Insufficient balance" in reason

    def test_validate_live_trade_success(self):
        """Test successful trade validation."""
        config = LiveModeConfig(
            enabled=True,
            daily_trade_limit_usd=100000.0,
            max_position_pct=1.0,
        )
        manager = LiveModeManager(config=config)

        is_valid, reason = manager.validate_live_trade(
            symbol="AAPL",
            amount=1.0,
            price=100.0,
            current_balance=10000.0,
        )

        assert is_valid is True
        assert reason == "Validation passed"

    def test_switch_mode_to_live(self):
        """Test switching to live mode."""
        config = LiveModeConfig(enabled=True)
        manager = LiveModeManager(config=config)

        # Initially in live mode since enabled=True
        assert manager.is_live_mode is True

        # Switch to simulated
        manager.switch_mode(TradingMode.SIMULATED)
        assert manager.is_live_mode is False
        assert manager.is_simulated_mode is True

        # Switch back to live
        manager.switch_mode(TradingMode.LIVE)
        assert manager.is_live_mode is True
        assert manager.is_simulated_mode is False

    def test_switch_mode_to_live_not_enabled(self):
        """Test cannot switch to live mode when not enabled in config."""
        config = LiveModeConfig(enabled=False)
        manager = LiveModeManager(config=config)

        result = manager.switch_mode(TradingMode.LIVE)
        assert result is False
        assert manager.is_live_mode is False

    def test_enable_disable_live_mode(self):
        """Test enable and disable live mode methods."""
        config = LiveModeConfig(enabled=False)
        manager = LiveModeManager(config=config)

        assert manager.is_live_mode is False

        # Enable live mode
        manager.enable_live_mode()
        assert manager.is_live_mode is True

        # Disable live mode
        manager.disable_live_mode()
        assert manager.is_live_mode is False

    def test_request_confirmation_without_provider(self):
        """Test confirmation request without provider auto-confirms."""
        config = LiveModeConfig(require_confirmation=True)
        manager = LiveModeManager(config=config)

        confirmed, code = manager.request_confirmation(
            symbol="AAPL",
            side="buy",
            amount=10.0,
            price=150.0,
        )

        assert confirmed is True
        assert "AUTO" in code

    def test_request_confirmation_not_required(self):
        """Test confirmation when not required."""
        config = LiveModeConfig(require_confirmation=False)
        manager = LiveModeManager(config=config)

        confirmed, code = manager.request_confirmation(
            symbol="AAPL",
            side="buy",
            amount=10.0,
            price=150.0,
        )

        assert confirmed is True
        assert code == "AUTO_CONFIRMED"

    def test_get_live_stats(self):
        """Test getting live trading statistics."""
        config = LiveModeConfig(
            enabled=True,
            daily_trade_limit_usd=50000.0,
            max_position_pct=0.3,
            require_confirmation=True,
        )
        manager = LiveModeManager(config=config)

        stats = manager.get_live_stats()

        assert stats["is_live"] is True
        assert stats["mode"] == "live"
        assert stats["daily_limit_usd"] == 50000.0
        assert stats["max_position_pct"] == 0.3
        assert stats["confirmation_required"] is True
        assert "daily_traded_usd" in stats
        assert "daily_remaining_usd" in stats
        assert "trade_count_today" in stats

    def test_repr(self):
        """Test string representation of LiveModeManager."""
        config = LiveModeConfig(enabled=True, daily_trade_limit_usd=50000.0)
        manager = LiveModeManager(config=config)

        repr_str = repr(manager)

        assert "LiveModeManager" in repr_str
        assert "live" in repr_str


class TestLiveTradeLogEntry:
    """Tests for LiveTradeLogEntry model."""

    def test_log_entry_creation(self):
        """Test creating a live trade log entry."""
        entry = LiveTradeLogEntry(
            timestamp="2024-01-01T10:00:00",
            symbol="AAPL",
            side="buy",
            amount=10.0,
            price=150.0,
            order_id="order123",
            confirmation_code="CONF123",
            risk_checks_passed=True,
            daily_limit_before=10000.0,
            daily_limit_after=8500.0,
        )

        assert entry.symbol == "AAPL"
        assert entry.side == "buy"
        assert entry.amount == 10.0
        assert entry.price == 150.0
        assert entry.risk_checks_passed is True
        assert entry.daily_limit_before == 10000.0
        assert entry.daily_limit_after == 8500.0

    def test_log_entry_amount_validation(self):
        """Test amount must be positive."""
        with pytest.raises(ValidationError):
            LiveTradeLogEntry(
                timestamp="2024-01-01T10:00:00",
                symbol="AAPL",
                side="buy",
                amount=0,
                price=150.0,
                order_id="order123",
                confirmation_code="CONF123",
                risk_checks_passed=True,
                daily_limit_before=10000.0,
                daily_limit_after=8500.0,
            )

    def test_log_entry_price_validation(self):
        """Test price must be positive."""
        with pytest.raises(ValidationError):
            LiveTradeLogEntry(
                timestamp="2024-01-01T10:00:00",
                symbol="AAPL",
                side="buy",
                amount=10.0,
                price=0,
                order_id="order123",
                confirmation_code="CONF123",
                risk_checks_passed=True,
                daily_limit_before=10000.0,
                daily_limit_after=8500.0,
            )

    def test_log_entry_limit_validation(self):
        """Test daily limits must be non-negative."""
        with pytest.raises(ValidationError):
            LiveTradeLogEntry(
                timestamp="2024-01-01T10:00:00",
                symbol="AAPL",
                side="buy",
                amount=10.0,
                price=150.0,
                order_id="order123",
                confirmation_code="CONF123",
                risk_checks_passed=True,
                daily_limit_before=-1000.0,
                daily_limit_after=8500.0,
            )

    def test_log_entry_default_metadata(self):
        """Test metadata defaults to empty dict."""
        entry = LiveTradeLogEntry(
            timestamp="2024-01-01T10:00:00",
            symbol="AAPL",
            side="buy",
            amount=10.0,
            price=150.0,
            order_id="order123",
            confirmation_code="CONF123",
            risk_checks_passed=True,
            daily_limit_before=10000.0,
            daily_limit_after=8500.0,
        )

        assert entry.metadata == {}

    def test_log_entry_with_metadata(self):
        """Test log entry with custom metadata."""
        entry = LiveTradeLogEntry(
            timestamp="2024-01-01T10:00:00",
            symbol="AAPL",
            side="buy",
            amount=10.0,
            price=150.0,
            order_id="order123",
            confirmation_code="CONF123",
            risk_checks_passed=True,
            daily_limit_before=10000.0,
            daily_limit_after=8500.0,
            metadata={"strategy": "momentum", "agent_id": "agent1"},
        )

        assert entry.metadata["strategy"] == "momentum"
        assert entry.metadata["agent_id"] == "agent1"
