"""FOMO score calculation."""

from datetime import datetime
from enum import Enum
from typing import Any

from pydantic import BaseModel

from ..signals.base import RiskLevel, SignalResult


class FOMOVerdict(str, Enum):
    """FOMO verdict categories."""

    GREEN = "green"      # 0-30: Low FOMO risk
    YELLOW = "yellow"    # 31-60: Moderate risk
    ORANGE = "orange"    # 61-80: High risk
    RED = "red"          # 81-100: Extreme risk

    @classmethod
    def from_score(cls, score: float) -> "FOMOVerdict":
        """Get verdict from score."""
        if score <= 30:
            return cls.GREEN
        elif score <= 60:
            return cls.YELLOW
        elif score <= 80:
            return cls.ORANGE
        else:
            return cls.RED


class FOMOScore(BaseModel):
    """Complete FOMO analysis score."""

    symbol: str
    score: float  # 0-100
    verdict: FOMOVerdict
    risk_level: RiskLevel
    signal_results: list[SignalResult]
    recommendation: str
    suggested_cooldown_hours: int
    timestamp: datetime
    warnings: list[str] = []  # Non-critical issues encountered

    model_config = {"arbitrary_types_allowed": True}

    @property
    def color(self) -> str:
        """Get color for display."""
        colors = {
            FOMOVerdict.GREEN: "green",
            FOMOVerdict.YELLOW: "yellow",
            FOMOVerdict.ORANGE: "orange",
            FOMOVerdict.RED: "red",
        }
        return colors[self.verdict]


class FOMOScorer:
    """Calculate FOMO scores from signal results."""

    # Score thresholds and their meanings
    THRESHOLDS = {
        "low": (0, 30),        # Reasonable entry
        "moderate": (31, 60),  # Proceed with caution
        "high": (61, 80),      # Strong FOMO indicators
        "extreme": (81, 100),  # Likely buying the top
    }

    # Cooldown suggestions based on score
    COOLDOWN_HOURS = {
        "low": 0,
        "moderate": 12,
        "high": 24,
        "extreme": 72,
    }

    def calculate(
        self, symbol: str, signal_results: list[SignalResult]
    ) -> FOMOScore:
        """Calculate overall FOMO score from signal results."""
        # Filter to available signals
        available = [s for s in signal_results if s.available]

        if not available:
            # No data available - return neutral score with warning
            return FOMOScore(
                symbol=symbol,
                score=50.0,
                verdict=FOMOVerdict.YELLOW,
                risk_level=RiskLevel.MODERATE,
                signal_results=signal_results,
                recommendation="Insufficient data for analysis - proceed with caution",
                suggested_cooldown_hours=24,
                timestamp=datetime.now(),
            )

        # Calculate weighted score
        total_weight = sum(s.weight for s in available)
        if total_weight == 0:
            weighted_score = 50.0
        else:
            weighted_score = sum(s.weighted_score for s in available) / total_weight

        # Determine verdict and risk level
        verdict = FOMOVerdict.from_score(weighted_score)
        risk_level = RiskLevel.from_score(weighted_score)

        # Generate recommendation
        recommendation = self._generate_recommendation(
            weighted_score, verdict, available
        )

        # Determine cooldown
        cooldown = self._get_cooldown_hours(weighted_score)

        return FOMOScore(
            symbol=symbol,
            score=round(weighted_score, 1),
            verdict=verdict,
            risk_level=risk_level,
            signal_results=signal_results,
            recommendation=recommendation,
            suggested_cooldown_hours=cooldown,
            timestamp=datetime.now(),
        )

    def _generate_recommendation(
        self,
        score: float,
        verdict: FOMOVerdict,
        signals: list[SignalResult],
    ) -> str:
        """Generate actionable recommendation."""
        if verdict == FOMOVerdict.GREEN:
            return (
                "Low FOMO risk - conditions appear favorable for entry. "
                "Always do your own research and only invest what you can afford to lose."
            )
        elif verdict == FOMOVerdict.YELLOW:
            # Find concerning signals
            concerns = [s for s in signals if s.score > 50]
            if concerns:
                concern_names = ", ".join(s.category.value for s in concerns[:2])
                return (
                    f"Moderate FOMO risk - some {concern_names} signals showing heat. "
                    "Consider waiting for a pullback or reducing position size."
                )
            return (
                "Moderate FOMO risk - mixed signals. "
                "Consider dollar-cost averaging instead of lump sum entry."
            )
        elif verdict == FOMOVerdict.ORANGE:
            high_risk = [s for s in signals if s.score >= 70]
            if high_risk:
                risk_names = ", ".join(s.category.value for s in high_risk)
                return (
                    f"High FOMO risk - strong warning signals from {risk_names}. "
                    "This could be a local top. Strongly consider waiting 24-48 hours."
                )
            return (
                "High FOMO risk - multiple signals indicate elevated risk. "
                "This is often when newcomers buy and regret. Consider waiting."
            )
        else:  # RED
            return (
                "EXTREME FOMO DETECTED! Multiple indicators suggest you may be "
                "buying near a local or all-time top. Historical data shows these "
                "conditions often precede corrections. WAIT at least 72 hours and "
                "reassess. Do not make emotional decisions."
            )

    def _get_cooldown_hours(self, score: float) -> int:
        """Get suggested cooldown hours based on score."""
        if score <= 30:
            return self.COOLDOWN_HOURS["low"]
        elif score <= 60:
            return self.COOLDOWN_HOURS["moderate"]
        elif score <= 80:
            return self.COOLDOWN_HOURS["high"]
        else:
            return self.COOLDOWN_HOURS["extreme"]

    def explain_score(self, fomo_score: FOMOScore) -> dict[str, Any]:
        """Generate detailed explanation of the score."""
        breakdown = []

        for signal in fomo_score.signal_results:
            signal_info = {
                "category": signal.category.value,
                "score": signal.score,
                "weight": signal.weight,
                "weighted_contribution": signal.weighted_score,
                "risk_level": signal.risk_level.value,
                "available": signal.available,
                "summary": signal.summary,
                "indicators": [
                    {
                        "name": i.name,
                        "value": i.value,
                        "score": i.score,
                        "description": i.description,
                    }
                    for i in signal.indicators
                ],
            }
            breakdown.append(signal_info)

        return {
            "overall_score": fomo_score.score,
            "verdict": fomo_score.verdict.value,
            "risk_level": fomo_score.risk_level.value,
            "signal_breakdown": breakdown,
            "recommendation": fomo_score.recommendation,
            "suggested_cooldown_hours": fomo_score.suggested_cooldown_hours,
        }
