"""
Tests for DirectionalFilters class.

Tests the SHORT and LONG validation logic with various indicator combinations.
"""
import pytest
import pandas as pd
import numpy as np
from src.models.signal_generator import DirectionalFilters


class TestDirectionalFilters:
    """Test suite for DirectionalFilters"""

    def test_short_valid_with_all_confirmations(self):
        """SHORT should be valid with 4 confirmations"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [60.0],       # > 55 ✓
            'sar': [2660.0],     # > close ✓
            'cmf': [-0.15],      # < 0 ✓
            'mfi': [58.0]        # > 55 ✓
        })
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        assert is_valid is True
        assert count == 4
        assert len(reasons) == 4

    def test_short_valid_with_2_confirmations(self):
        """SHORT should be valid with exactly 2 confirmations"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [60.0],       # > 55 ✓
            'sar': [2660.0],     # > close ✓
            'cmf': [0.1],        # > 0 ✗
            'mfi': [45.0]        # < 55 ✗
        })
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        assert is_valid is True
        assert count == 2

    def test_short_invalid_with_1_confirmation(self):
        """SHORT should be invalid with only 1 confirmation"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [60.0],       # > 55 ✓
            'sar': [2640.0],     # < close ✗
            'cmf': [0.1],        # > 0 ✗
            'mfi': [45.0]        # < 55 ✗
        })
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        assert is_valid is False
        assert count == 1

    def test_short_invalid_empty_df(self):
        """SHORT should be invalid with empty DataFrame"""
        df = pd.DataFrame()
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        assert is_valid is False
        assert count == 0
        assert "Empty DataFrame" in reasons

    def test_short_none_df(self):
        """SHORT should be invalid with None DataFrame"""
        is_valid, count, reasons = DirectionalFilters.is_short_valid(None, 'XAUUSD')
        assert is_valid is False
        assert count == 0

    def test_long_valid_with_all_confirmations(self):
        """LONG should be valid with 4 confirmations"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [30.0],       # < 35 ✓
            'sar': [2640.0],     # < close ✓
            'cmf': [0.15],       # > 0.1 ✓
            'mfi': [30.0]        # < 35 ✓
        })
        is_valid, count, reasons = DirectionalFilters.is_long_valid(df, 'XAUUSD')
        assert is_valid is True
        assert count == 4
        assert len(reasons) == 4

    def test_long_valid_with_3_confirmations(self):
        """LONG should be valid with exactly 3 confirmations"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [30.0],       # < 35 ✓
            'sar': [2640.0],     # < close ✓
            'cmf': [0.15],       # > 0.1 ✓
            'mfi': [40.0]        # < 35 ✗
        })
        is_valid, count, reasons = DirectionalFilters.is_long_valid(df, 'XAUUSD')
        assert is_valid is True
        assert count == 3

    def test_long_invalid_with_2_confirmations(self):
        """LONG should be INVALID with only 2 confirmations (stricter than SHORT)"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [30.0],       # < 35 ✓
            'sar': [2640.0],     # < close ✓
            'cmf': [0.05],       # > 0.1 ✗
            'mfi': [40.0]        # < 35 ✗
        })
        is_valid, count, reasons = DirectionalFilters.is_long_valid(df, 'XAUUSD')
        assert is_valid is False
        assert count == 2

    def test_long_invalid_empty_df(self):
        """LONG should be invalid with empty DataFrame"""
        df = pd.DataFrame()
        is_valid, count, reasons = DirectionalFilters.is_long_valid(df, 'XAUUSD')
        assert is_valid is False
        assert count == 0

    def test_handles_missing_columns(self):
        """Should handle DataFrames with missing indicator columns"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [60.0]  # Only RSI available
        })
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        assert is_valid is False
        assert count == 1  # Only RSI counts

    def test_handles_nan_values(self):
        """Should handle NaN values in indicators"""
        df = pd.DataFrame({
            'close': [2650.0],
            'rsi': [np.nan],
            'sar': [2660.0],
            'cmf': [-0.1],
            'mfi': [58.0]
        })
        is_valid, count, reasons = DirectionalFilters.is_short_valid(df, 'XAUUSD')
        # RSI is NaN, so only 3 confirmations
        assert count == 3
        assert is_valid is True


class TestFeatureFlags:
    """Test suite for FeatureFlags"""

    def test_feature_flags_import(self):
        """Should be able to import FeatureFlags"""
        from src.config.feature_flags import FeatureFlags
        assert hasattr(FeatureFlags, 'USE_SYMBOL_TRAINERS')
        assert hasattr(FeatureFlags, 'USE_DIRECTIONAL_FILTERS')
        assert hasattr(FeatureFlags, 'USE_CENTRALIZED_CONFIGS')

    def test_feature_flags_status(self):
        """Should return status dict"""
        from src.config.feature_flags import FeatureFlags
        status = FeatureFlags.status()
        assert isinstance(status, dict)
        assert 'USE_SYMBOL_TRAINERS' in status
        assert 'USE_DIRECTIONAL_FILTERS' in status
        assert 'USE_CENTRALIZED_CONFIGS' in status


class TestPriceDataGenerator:
    """Test suite for refactored PriceDataGenerator"""

    def test_generator_uses_symbol_configs(self):
        """Should use SYMBOL_CONFIGS for known symbols"""
        from src.models.range_predictor_factor import PriceDataGenerator
        from src.training.symbol_timeframe_trainer import SYMBOL_CONFIGS

        for symbol in ['XAUUSD', 'BTCUSD', 'EURUSD']:
            if symbol in SYMBOL_CONFIGS:
                generator = PriceDataGenerator(symbol)
                assert generator.config['factor'] == SYMBOL_CONFIGS[symbol].base_factor

    def test_generator_fallback_unknown_symbol(self):
        """Should use fallback for unknown symbols"""
        from src.models.range_predictor_factor import PriceDataGenerator

        generator = PriceDataGenerator('UNKNOWN_SYMBOL')
        assert generator.config['base'] == 100.0
        assert generator.config['factor'] == 1.0

    def test_generator_generates_data(self):
        """Should generate valid OHLCV data"""
        from src.models.range_predictor_factor import PriceDataGenerator

        generator = PriceDataGenerator('XAUUSD')
        df = generator.generate(days=5, timeframe='5m')

        assert len(df) > 0
        assert 'Open' in df.columns
        assert 'High' in df.columns
        assert 'Low' in df.columns
        assert 'Close' in df.columns
        assert 'Volume' in df.columns


if __name__ == '__main__':
    pytest.main([__file__, '-v'])
