"""Tests for FOMO scorer."""

import pytest
from datetime import datetime

from fomo_guard.core.scorer import FOMOScorer, FOMOScore, FOMOVerdict
from fomo_guard.signals.base import (
    Signal,
    SignalCategory,
    SignalResult,
    SignalIndicator,
    RiskLevel,
)


class TestFOMOVerdict:
    """Tests for FOMOVerdict enum."""

    def test_from_score_green(self):
        assert FOMOVerdict.from_score(0) == FOMOVerdict.GREEN
        assert FOMOVerdict.from_score(15) == FOMOVerdict.GREEN
        assert FOMOVerdict.from_score(30) == FOMOVerdict.GREEN

    def test_from_score_yellow(self):
        assert FOMOVerdict.from_score(31) == FOMOVerdict.YELLOW
        assert FOMOVerdict.from_score(45) == FOMOVerdict.YELLOW
        assert FOMOVerdict.from_score(60) == FOMOVerdict.YELLOW

    def test_from_score_orange(self):
        assert FOMOVerdict.from_score(61) == FOMOVerdict.ORANGE
        assert FOMOVerdict.from_score(70) == FOMOVerdict.ORANGE
        assert FOMOVerdict.from_score(80) == FOMOVerdict.ORANGE

    def test_from_score_red(self):
        assert FOMOVerdict.from_score(81) == FOMOVerdict.RED
        assert FOMOVerdict.from_score(90) == FOMOVerdict.RED
        assert FOMOVerdict.from_score(100) == FOMOVerdict.RED


class TestFOMOScorer:
    """Tests for FOMOScorer."""

    def setup_method(self):
        """Set up test fixtures."""
        self.scorer = FOMOScorer()

    def _create_signal_result(
        self,
        category: SignalCategory,
        score: float,
        weight: float = 0.33,
        available: bool = True,
    ) -> SignalResult:
        """Helper to create a signal result."""
        return SignalResult(
            category=category,
            score=score,
            weight=weight,
            indicators=[],
            risk_level=RiskLevel.from_score(score),
            summary="Test summary",
            available=available,
        )

    def test_calculate_single_signal(self):
        """Test calculation with a single signal."""
        signals = [
            self._create_signal_result(SignalCategory.PRICE, 50.0, 1.0)
        ]
        result = self.scorer.calculate("BTC", signals)

        assert result.symbol == "BTC"
        assert result.score == 50.0
        assert result.verdict == FOMOVerdict.YELLOW
        assert result.warnings == []

    def test_calculate_weighted_average(self):
        """Test weighted average calculation."""
        signals = [
            self._create_signal_result(SignalCategory.PRICE, 80.0, 0.4),
            self._create_signal_result(SignalCategory.SOCIAL, 40.0, 0.3),
            self._create_signal_result(SignalCategory.ONCHAIN, 60.0, 0.3),
        ]
        result = self.scorer.calculate("ETH", signals)

        # Weighted: (80*0.4 + 40*0.3 + 60*0.3) / 1.0 = 62
        assert result.score == 62.0
        assert result.verdict == FOMOVerdict.ORANGE

    def test_calculate_with_unavailable_signal(self):
        """Test calculation when some signals are unavailable."""
        signals = [
            self._create_signal_result(SignalCategory.PRICE, 50.0, 0.4, available=True),
            self._create_signal_result(SignalCategory.SOCIAL, 80.0, 0.3, available=False),
            self._create_signal_result(SignalCategory.ONCHAIN, 60.0, 0.3, available=True),
        ]
        result = self.scorer.calculate("BTC", signals)

        # Only available signals: (50*0.4 + 60*0.3) / 0.7 ≈ 54.3
        expected = (50 * 0.4 + 60 * 0.3) / 0.7
        assert abs(result.score - expected) < 0.1

    def test_calculate_no_available_signals(self):
        """Test calculation when no signals are available."""
        signals = [
            self._create_signal_result(SignalCategory.PRICE, 50.0, 0.4, available=False),
        ]
        result = self.scorer.calculate("BTC", signals)

        assert result.score == 50.0  # Default neutral
        assert result.verdict == FOMOVerdict.YELLOW

    def test_cooldown_hours_low_score(self):
        """Test suggested cooldown for low scores."""
        signals = [self._create_signal_result(SignalCategory.PRICE, 20.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)

        assert result.suggested_cooldown_hours == 0

    def test_cooldown_hours_extreme_score(self):
        """Test suggested cooldown for extreme scores."""
        signals = [self._create_signal_result(SignalCategory.PRICE, 90.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)

        assert result.suggested_cooldown_hours == 72

    def test_recommendation_green(self):
        """Test recommendation for green verdict."""
        signals = [self._create_signal_result(SignalCategory.PRICE, 20.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)

        assert "Low FOMO risk" in result.recommendation

    def test_recommendation_red(self):
        """Test recommendation for red verdict."""
        signals = [self._create_signal_result(SignalCategory.PRICE, 95.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)

        assert "EXTREME" in result.recommendation
        assert "WAIT" in result.recommendation

    def test_fomo_score_color_property(self):
        """Test FOMOScore color property."""
        signals = [self._create_signal_result(SignalCategory.PRICE, 20.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)
        assert result.color == "green"

        signals = [self._create_signal_result(SignalCategory.PRICE, 90.0, 1.0)]
        result = self.scorer.calculate("BTC", signals)
        assert result.color == "red"


class TestRiskLevel:
    """Tests for RiskLevel enum."""

    def test_from_score(self):
        assert RiskLevel.from_score(0) == RiskLevel.LOW
        assert RiskLevel.from_score(30) == RiskLevel.LOW
        assert RiskLevel.from_score(31) == RiskLevel.MODERATE
        assert RiskLevel.from_score(60) == RiskLevel.MODERATE
        assert RiskLevel.from_score(61) == RiskLevel.HIGH
        assert RiskLevel.from_score(80) == RiskLevel.HIGH
        assert RiskLevel.from_score(81) == RiskLevel.EXTREME
        assert RiskLevel.from_score(100) == RiskLevel.EXTREME
