"""Tests for intelligent autopilot functionality."""

import pytest
from decimal import Decimal
from unittest.mock import Mock, patch, AsyncMock
from src.core.database import OrderSide, OrderType


class TestPreFlightValidation:
    """Tests for pre-flight order validation."""
    
    @pytest.fixture
    def mock_autopilot(self):
        """Create mock autopilot with necessary attributes."""
        from src.autopilot.intelligent_autopilot import IntelligentAutopilot
        
        with patch.object(IntelligentAutopilot, '__init__', lambda x, *args, **kwargs: None):
            autopilot = IntelligentAutopilot.__new__(IntelligentAutopilot)
            autopilot.symbol = 'BTC/USD'
            autopilot.paper_trading = True
            autopilot.logger = Mock()
            
            # Mock trading engine
            autopilot.trading_engine = Mock()
            autopilot.trading_engine.paper_trading = Mock()
            autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('1000.0')
            autopilot.trading_engine.paper_trading.get_positions.return_value = []
            
            return autopilot
    
    @pytest.mark.asyncio
    async def test_can_execute_order_insufficient_funds(self, mock_autopilot):
        """Test that insufficient funds returns False."""
        mock_autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('10.0')
        
        can_execute, reason = await mock_autopilot._can_execute_order(
            side=OrderSide.BUY,
            quantity=Decimal('1.0'),
            price=Decimal('100.0')
        )
        
        assert can_execute is False
        assert 'Insufficient funds' in reason
    
    @pytest.mark.asyncio
    async def test_can_execute_order_sufficient_funds(self, mock_autopilot):
        """Test that sufficient funds returns True."""
        mock_autopilot.trading_engine.paper_trading.get_balance.return_value = Decimal('1000.0')
        
        can_execute, reason = await mock_autopilot._can_execute_order(
            side=OrderSide.BUY,
            quantity=Decimal('1.0'),
            price=Decimal('100.0')
        )
        
        assert can_execute is True
        assert reason == 'OK'
    
    @pytest.mark.asyncio
    async def test_can_execute_order_no_position_for_sell(self, mock_autopilot):
        """Test that SELL without position returns False."""
        mock_autopilot.trading_engine.paper_trading.get_positions.return_value = []
        
        can_execute, reason = await mock_autopilot._can_execute_order(
            side=OrderSide.SELL,
            quantity=Decimal('1.0'),
            price=Decimal('100.0')
        )
        
        assert can_execute is False
        assert 'No position to sell' in reason
    
    @pytest.mark.asyncio
    async def test_can_execute_order_minimum_value(self, mock_autopilot):
        """Test that order below minimum value returns False."""
        can_execute, reason = await mock_autopilot._can_execute_order(
            side=OrderSide.BUY,
            quantity=Decimal('0.001'),
            price=Decimal('0.10')  # Order value = $0.0001
        )
        
        assert can_execute is False
        assert 'below minimum' in reason


class TestSmartOrderTypeSelection:
    """Tests for smart order type selection."""
    
    @pytest.fixture
    def mock_autopilot(self):
        """Create mock autopilot for order type tests."""
        from src.autopilot.intelligent_autopilot import IntelligentAutopilot
        
        with patch.object(IntelligentAutopilot, '__init__', lambda x, *args, **kwargs: None):
            autopilot = IntelligentAutopilot.__new__(IntelligentAutopilot)
            autopilot.logger = Mock()
            return autopilot
    
    def test_strong_signal_uses_market(self, mock_autopilot):
        """Test that strong signals (>80%) use MARKET orders."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.BUY,
            signal_strength=0.85,
            current_price=Decimal('100.0'),
            is_stop_loss=False
        )
        
        assert order_type == OrderType.MARKET
        assert price is None
    
    def test_normal_signal_uses_limit(self, mock_autopilot):
        """Test that normal signals use LIMIT orders."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.BUY,
            signal_strength=0.65,
            current_price=Decimal('100.0'),
            is_stop_loss=False
        )
        
        assert order_type == OrderType.LIMIT
        assert price is not None
        # BUY limit should be below market
        assert price < Decimal('100.0')
    
    def test_stop_loss_uses_market(self, mock_autopilot):
        """Test that stop-loss exits use MARKET orders."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.SELL,
            signal_strength=0.5,
            current_price=Decimal('100.0'),
            is_stop_loss=True
        )
        
        assert order_type == OrderType.MARKET
        assert price is None
    
    def test_take_profit_uses_limit(self, mock_autopilot):
        """Test that take-profit exits can use LIMIT orders."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.SELL,
            signal_strength=0.6,
            current_price=Decimal('100.0'),
            is_stop_loss=False
        )
        
        assert order_type == OrderType.LIMIT
        assert price is not None
        # SELL limit should be above market
        assert price > Decimal('100.0')
    
    def test_buy_limit_price_discount(self, mock_autopilot):
        """Test BUY LIMIT price is 0.1% below market."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.BUY,
            signal_strength=0.6,
            current_price=Decimal('1000.00'),
            is_stop_loss=False
        )
        
        # 0.1% discount = 999.00
        expected = Decimal('999.00')
        assert price == expected
    
    def test_sell_limit_price_premium(self, mock_autopilot):
        """Test SELL LIMIT price is 0.1% above market."""
        order_type, price = mock_autopilot._determine_order_type_and_price(
            side=OrderSide.SELL,
            signal_strength=0.6,
            current_price=Decimal('1000.00'),
            is_stop_loss=False
        )
        
        # 0.1% premium = 1001.00
        expected = Decimal('1001.00')
        assert price == expected
