"""Tests for signal analyzers."""

import pytest

from fomo_guard.signals.price import PriceSignal
from fomo_guard.signals.social import SocialSignal
from fomo_guard.signals.onchain import OnChainSignal
from fomo_guard.signals.base import SignalCategory, RiskLevel


class TestPriceSignal:
    """Tests for price signal analysis."""

    def setup_method(self):
        """Set up test fixtures."""
        self.signal = PriceSignal()

    @pytest.mark.asyncio
    async def test_analyze_no_data(self):
        """Test analysis with no price data."""
        result = await self.signal.analyze("BTC", {})

        assert result.category == SignalCategory.PRICE
        assert result.available is False
        assert len(result.indicators) == 0

    @pytest.mark.asyncio
    async def test_analyze_basic_data(self):
        """Test analysis with basic price data."""
        data = {
            "current_price": 50000,
            "ath": 69000,
            "ath_change_percentage": -27.5,
            "price_change_24h": 5.0,
            "price_change_7d": 15.0,
            "high_24h": 51000,
            "low_24h": 48000,
        }
        result = await self.signal.analyze("BTC", data)

        assert result.category == SignalCategory.PRICE
        assert result.available is True
        assert result.weight == 0.40
        assert len(result.indicators) > 0

    @pytest.mark.asyncio
    async def test_ath_proximity_high(self):
        """Test ATH proximity indicator when close to ATH."""
        data = {
            "current_price": 68000,
            "ath": 69000,
            "ath_change_percentage": -1.5,
        }
        result = await self.signal.analyze("BTC", data)

        ath_indicator = next(
            (i for i in result.indicators if i.name == "ATH Proximity"), None
        )
        assert ath_indicator is not None
        assert ath_indicator.score >= 90  # Should be extreme risk

    @pytest.mark.asyncio
    async def test_ath_proximity_low(self):
        """Test ATH proximity indicator when far from ATH."""
        data = {
            "current_price": 30000,
            "ath": 69000,
            "ath_change_percentage": -56.5,
        }
        result = await self.signal.analyze("BTC", data)

        ath_indicator = next(
            (i for i in result.indicators if i.name == "ATH Proximity"), None
        )
        assert ath_indicator is not None
        assert ath_indicator.score <= 30  # Should be low risk

    @pytest.mark.asyncio
    async def test_price_pump_detection(self):
        """Test pump detection with large price change."""
        data = {
            "current_price": 50000,
            "ath": 100000,
            "ath_change_percentage": -50,
            "price_change_24h": 25.0,  # 25% pump
        }
        result = await self.signal.analyze("BTC", data)

        change_indicator = next(
            (i for i in result.indicators if "24h" in i.name), None
        )
        assert change_indicator is not None
        assert change_indicator.score >= 80  # Extreme pump

    @pytest.mark.asyncio
    async def test_rsi_calculation(self):
        """Test RSI calculation from sparkline data."""
        # Create a rising price pattern
        prices = [100 + i * 2 for i in range(20)]  # Steadily rising

        data = {
            "current_price": prices[-1],
            "ath": 200,
            "ath_change_percentage": -30,
            "sparkline_7d": prices,
        }
        result = await self.signal.analyze("BTC", data)

        rsi_indicator = next(
            (i for i in result.indicators if "RSI" in i.name), None
        )
        assert rsi_indicator is not None
        # Strong uptrend should have high RSI
        assert rsi_indicator.value >= 70


class TestSocialSignal:
    """Tests for social signal analysis."""

    def setup_method(self):
        """Set up test fixtures."""
        self.signal = SocialSignal()

    @pytest.mark.asyncio
    async def test_analyze_no_data(self):
        """Test analysis with no social data."""
        result = await self.signal.analyze("BTC", {})

        assert result.category == SignalCategory.SOCIAL
        assert result.available is False

    @pytest.mark.asyncio
    async def test_analyze_twitter_data(self):
        """Test analysis with Twitter data."""
        data = {
            "twitter": {
                "mention_velocity": 300,
                "sentiment_score": 0.7,
                "bullish_ratio": 0.85,
            }
        }
        result = await self.signal.analyze("BTC", data)

        assert result.category == SignalCategory.SOCIAL
        assert result.available is True
        assert len(result.indicators) > 0

    @pytest.mark.asyncio
    async def test_extreme_bullishness(self):
        """Test detection of extreme bullish sentiment."""
        data = {
            "twitter": {
                "bullish_ratio": 0.95,  # Echo chamber
            }
        }
        result = await self.signal.analyze("BTC", data)

        bullish_indicator = next(
            (i for i in result.indicators if "Bullish" in i.name), None
        )
        assert bullish_indicator is not None
        assert bullish_indicator.score >= 90  # Extreme risk

    @pytest.mark.asyncio
    async def test_lunarcrush_galaxy_score(self):
        """Test LunarCrush Galaxy Score analysis."""
        data = {
            "lunarcrush": {
                "galaxy_score": 85,
                "social_volume_change_24h": 150,
            }
        }
        result = await self.signal.analyze("BTC", data)

        galaxy_indicator = next(
            (i for i in result.indicators if "Galaxy" in i.name), None
        )
        assert galaxy_indicator is not None
        assert galaxy_indicator.score >= 80  # High hype


class TestOnChainSignal:
    """Tests for on-chain signal analysis."""

    def setup_method(self):
        """Set up test fixtures."""
        self.signal = OnChainSignal()

    @pytest.mark.asyncio
    async def test_analyze_no_data(self):
        """Test analysis with no on-chain data."""
        result = await self.signal.analyze("BTC", {})

        assert result.category == SignalCategory.ONCHAIN
        assert result.available is False

    @pytest.mark.asyncio
    async def test_exchange_inflow(self):
        """Test exchange inflow analysis."""
        data = {
            "glassnode": {
                "exchange_netflow": 50000,  # Large inflow
            }
        }
        result = await self.signal.analyze("BTC", data)

        netflow_indicator = next(
            (i for i in result.indicators if "Netflow" in i.name), None
        )
        assert netflow_indicator is not None
        assert netflow_indicator.score >= 80  # Distribution risk

    @pytest.mark.asyncio
    async def test_supply_in_profit(self):
        """Test supply in profit analysis."""
        data = {
            "glassnode": {
                "supply_in_profit_percent": 0.97,  # 97% in profit
            }
        }
        result = await self.signal.analyze("BTC", data)

        supply_indicator = next(
            (i for i in result.indicators if "Supply" in i.name), None
        )
        assert supply_indicator is not None
        assert supply_indicator.score >= 90  # Extreme sell pressure risk

    @pytest.mark.asyncio
    async def test_gas_price_analysis(self):
        """Test Ethereum gas price analysis."""
        data = {
            "etherscan": {
                "gas_price_gwei": 250,  # High gas
            }
        }
        result = await self.signal.analyze("ETH", data)

        gas_indicator = next(
            (i for i in result.indicators if "Gas" in i.name), None
        )
        assert gas_indicator is not None
        assert gas_indicator.score >= 80  # High network activity
