"""Tests for ATR-based stop loss."""

import pytest
import pandas as pd
from decimal import Decimal
from src.risk.stop_loss import StopLossManager


class TestATRStopLoss:
    """Tests for ATR-based stop loss functionality."""
    
    @pytest.fixture
    def stop_loss_manager(self):
        """Create stop loss manager instance."""
        return StopLossManager()
    
    @pytest.fixture
    def sample_ohlcv_data(self):
        """Create sample OHLCV data."""
        dates = pd.date_range(start='2025-01-01', periods=50, freq='1H')
        base_price = 50000
        return pd.DataFrame({
            'high': [base_price + 100 + i * 10 for i in range(50)],
            'low': [base_price - 100 + i * 10 for i in range(50)],
            'close': [base_price + i * 10 for i in range(50)],
            'open': [base_price - 50 + i * 10 for i in range(50)],
            'volume': [1000.0] * 50
        }, index=dates)
    
    def test_set_atr_stop_loss(self, stop_loss_manager, sample_ohlcv_data):
        """Test setting ATR-based stop loss."""
        position_id = 1
        entry_price = Decimal("50000")
        
        stop_loss_manager.set_stop_loss(
            position_id=position_id,
            stop_price=entry_price,
            use_atr=True,
            atr_multiplier=Decimal('2.0'),
            atr_period=14,
            ohlcv_data=sample_ohlcv_data
        )
        
        assert position_id in stop_loss_manager.stop_losses
        config = stop_loss_manager.stop_losses[position_id]
        assert config['use_atr'] is True
        assert config['atr_multiplier'] == Decimal('2.0')
        assert config['atr_period'] == 14
        assert 'stop_price' in config
    
    def test_calculate_atr_stop(self, stop_loss_manager, sample_ohlcv_data):
        """Test calculating ATR stop price."""
        entry_price = Decimal("50000")
        
        stop_price_long = stop_loss_manager.calculate_atr_stop(
            entry_price=entry_price,
            is_long=True,
            ohlcv_data=sample_ohlcv_data,
            atr_multiplier=Decimal('2.0'),
            atr_period=14
        )
        
        stop_price_short = stop_loss_manager.calculate_atr_stop(
            entry_price=entry_price,
            is_long=False,
            ohlcv_data=sample_ohlcv_data,
            atr_multiplier=Decimal('2.0'),
            atr_period=14
        )
        
        # Long position: stop should be below entry
        assert stop_price_long < entry_price
        
        # Short position: stop should be above entry
        assert stop_price_short > entry_price
    
    def test_atr_trailing_stop(self, stop_loss_manager, sample_ohlcv_data):
        """Test ATR-based trailing stop."""
        position_id = 1
        entry_price = Decimal("50000")
        
        stop_loss_manager.set_stop_loss(
            position_id=position_id,
            stop_price=entry_price,
            trailing=True,
            use_atr=True,
            atr_multiplier=Decimal('2.0'),
            atr_period=14,
            ohlcv_data=sample_ohlcv_data
        )
        
        # Check stop loss with higher price (should update trailing stop)
        current_price = Decimal("51000")
        triggered = stop_loss_manager.check_stop_loss(
            position_id=position_id,
            current_price=current_price,
            is_long=True,
            ohlcv_data=sample_ohlcv_data
        )
        
        # Should not trigger at higher price
        assert triggered is False
    
    def test_atr_stop_insufficient_data(self, stop_loss_manager):
        """Test ATR stop with insufficient data falls back to percentage."""
        entry_price = Decimal("50000")
        insufficient_data = pd.DataFrame({
            'high': [51000],
            'low': [49000],
            'close': [50000]
        })
        
        stop_price = stop_loss_manager.calculate_atr_stop(
            entry_price=entry_price,
            is_long=True,
            ohlcv_data=insufficient_data,
            atr_period=14
        )
        
        # Should fall back to percentage-based stop (2%)
        assert stop_price == entry_price * Decimal('0.98')

