"""Price and technical signal analysis."""

from typing import Any

from .base import Signal, SignalCategory, SignalIndicator, SignalResult


class PriceSignal(Signal):
    """Analyze price and technical indicators for FOMO signals."""

    category = SignalCategory.PRICE
    weight = 0.40  # 40% weight in final score

    async def analyze(self, symbol: str, data: dict[str, Any]) -> SignalResult:
        """Analyze price signals."""
        indicators = []

        # Check if we have price data
        if not data.get("current_price"):
            return self._create_result(
                indicators=[],
                summary="Price data unavailable",
                available=False,
            )

        # ATH proximity analysis
        ath_indicator = self._analyze_ath_proximity(data)
        if ath_indicator:
            indicators.append(ath_indicator)

        # Price change analysis (pump detection)
        change_indicators = self._analyze_price_changes(data)
        indicators.extend(change_indicators)

        # Volatility analysis
        vol_indicator = self._analyze_volatility(data)
        if vol_indicator:
            indicators.append(vol_indicator)

        # RSI analysis (if sparkline data available)
        rsi_indicator = self._analyze_rsi(data)
        if rsi_indicator:
            indicators.append(rsi_indicator)

        score = self._calculate_score(indicators)
        summary = self._generate_summary(score, indicators)

        return self._create_result(indicators, summary)

    def _analyze_ath_proximity(self, data: dict[str, Any]) -> SignalIndicator | None:
        """Analyze how close current price is to ATH."""
        ath = data.get("ath")
        current = data.get("current_price")
        ath_change = data.get("ath_change_percentage")

        if not all([ath, current, ath_change is not None]):
            return None

        # ath_change is negative (% from ATH), we want proximity
        proximity = 100 + ath_change  # 0 = at ATH bottom, 100 = at ATH

        # Higher proximity = higher FOMO risk
        # Being within 10% of ATH = extreme FOMO risk
        if proximity >= 90:
            score = 95
            desc = f"Within {100 - proximity:.1f}% of all-time high - extreme FOMO risk"
        elif proximity >= 80:
            score = 80
            desc = f"{100 - proximity:.1f}% from ATH - high FOMO risk"
        elif proximity >= 60:
            score = 60
            desc = f"{100 - proximity:.1f}% from ATH - moderate risk"
        elif proximity >= 40:
            score = 35
            desc = f"{100 - proximity:.1f}% from ATH - reasonable entry"
        else:
            score = 15
            desc = f"{100 - proximity:.1f}% from ATH - significant discount"

        return SignalIndicator(
            name="ATH Proximity",
            value=proximity,
            score=score,
            description=desc,
            raw_value={"ath": ath, "current": current, "change": ath_change},
        )

    def _analyze_price_changes(self, data: dict[str, Any]) -> list[SignalIndicator]:
        """Analyze price changes for pump detection."""
        indicators = []

        # 24h change
        change_24h = data.get("price_change_24h")
        if change_24h is not None:
            score = self._price_change_to_score(change_24h, "24h")
            indicators.append(
                SignalIndicator(
                    name="24h Price Change",
                    value=change_24h,
                    score=score,
                    description=self._describe_price_change(change_24h, "24h"),
                    raw_value=change_24h,
                )
            )

        # 7d change
        change_7d = data.get("price_change_7d")
        if change_7d is not None:
            score = self._price_change_to_score(change_7d, "7d")
            indicators.append(
                SignalIndicator(
                    name="7d Price Change",
                    value=change_7d,
                    score=score,
                    description=self._describe_price_change(change_7d, "7d"),
                    raw_value=change_7d,
                )
            )

        return indicators

    def _price_change_to_score(self, change: float, period: str) -> float:
        """Convert price change to FOMO score."""
        # Different thresholds for different periods
        thresholds = {
            "24h": {"extreme": 20, "high": 10, "moderate": 5},
            "7d": {"extreme": 50, "high": 30, "moderate": 15},
        }
        t = thresholds.get(period, thresholds["24h"])

        if change >= t["extreme"]:
            return 90 + min(10, (change - t["extreme"]) / 5)  # Cap at 100
        elif change >= t["high"]:
            return 70 + (change - t["high"]) / (t["extreme"] - t["high"]) * 20
        elif change >= t["moderate"]:
            return 50 + (change - t["moderate"]) / (t["high"] - t["moderate"]) * 20
        elif change >= 0:
            return 20 + change / t["moderate"] * 30
        else:
            # Negative changes reduce FOMO (buying dip)
            return max(0, 20 + change)

    def _describe_price_change(self, change: float, period: str) -> str:
        """Generate description for price change."""
        direction = "up" if change >= 0 else "down"
        abs_change = abs(change)

        if abs_change >= 20:
            intensity = "extreme pump" if change > 0 else "crash"
        elif abs_change >= 10:
            intensity = "significant move"
        elif abs_change >= 5:
            intensity = "moderate move"
        else:
            intensity = "stable"

        return f"Price {direction} {abs_change:.1f}% in {period} - {intensity}"

    def _analyze_volatility(self, data: dict[str, Any]) -> SignalIndicator | None:
        """Analyze price volatility from 24h high/low."""
        high = data.get("high_24h")
        low = data.get("low_24h")
        current = data.get("current_price")

        if not all([high, low, current]):
            return None

        # Calculate volatility as % range
        volatility = ((high - low) / low) * 100 if low > 0 else 0

        # Higher volatility = higher risk/FOMO
        if volatility >= 15:
            score = 85
            desc = f"Extreme volatility ({volatility:.1f}% range)"
        elif volatility >= 10:
            score = 65
            desc = f"High volatility ({volatility:.1f}% range)"
        elif volatility >= 5:
            score = 45
            desc = f"Moderate volatility ({volatility:.1f}% range)"
        else:
            score = 20
            desc = f"Low volatility ({volatility:.1f}% range)"

        return SignalIndicator(
            name="24h Volatility",
            value=volatility,
            score=score,
            description=desc,
            raw_value={"high": high, "low": low},
        )

    def _analyze_rsi(self, data: dict[str, Any]) -> SignalIndicator | None:
        """Calculate and analyze RSI from sparkline data."""
        sparkline = data.get("sparkline_7d")
        if not sparkline or len(sparkline) < 14:
            return None

        rsi = self._calculate_rsi(sparkline)

        # RSI interpretation
        if rsi >= 80:
            score = 95
            desc = f"RSI {rsi:.0f} - Extremely overbought"
        elif rsi >= 70:
            score = 80
            desc = f"RSI {rsi:.0f} - Overbought territory"
        elif rsi >= 60:
            score = 55
            desc = f"RSI {rsi:.0f} - Bullish momentum"
        elif rsi >= 40:
            score = 30
            desc = f"RSI {rsi:.0f} - Neutral zone"
        elif rsi >= 30:
            score = 20
            desc = f"RSI {rsi:.0f} - Oversold potential"
        else:
            score = 10
            desc = f"RSI {rsi:.0f} - Deeply oversold"

        return SignalIndicator(
            name="RSI (7d)",
            value=rsi,
            score=score,
            description=desc,
            raw_value=rsi,
        )

    def _calculate_rsi(self, prices: list[float], period: int = 14) -> float:
        """Calculate RSI from price series."""
        if len(prices) < period + 1:
            return 50.0  # Default neutral

        # Calculate price changes
        changes = [prices[i] - prices[i - 1] for i in range(1, len(prices))]

        # Use last 'period' changes
        recent_changes = changes[-period:]

        gains = [c if c > 0 else 0 for c in recent_changes]
        losses = [-c if c < 0 else 0 for c in recent_changes]

        avg_gain = sum(gains) / period
        avg_loss = sum(losses) / period

        if avg_loss == 0:
            return 100.0

        rs = avg_gain / avg_loss
        rsi = 100 - (100 / (1 + rs))

        return rsi

    def _generate_summary(
        self, score: float, indicators: list[SignalIndicator]
    ) -> str:
        """Generate a summary of price signals."""
        if not indicators:
            return "Insufficient price data for analysis"

        high_risk = [i for i in indicators if i.score >= 70]
        if high_risk:
            names = ", ".join(i.name for i in high_risk[:2])
            return f"High FOMO risk from price signals: {names}"
        elif score >= 50:
            return "Moderate FOMO risk - price showing some heat"
        else:
            return "Price signals suggest reasonable entry conditions"
