"""Sentiment-Driven Strategy - Trades based on news sentiment and market fear/greed."""

from decimal import Decimal
from typing import Dict, Any, Optional, List
import asyncio
from datetime import datetime, timedelta

from ..base import BaseStrategy, StrategySignal, SignalType
from src.data.news_collector import get_news_collector
from src.core.logger import get_logger
from src.core.config import get_config

logger = get_logger(__name__)


class SentimentStrategy(BaseStrategy):
    """
    Sentiment-Driven Strategy that trades based on news sentiment and market fear.
    
    Modes:
    1. Contrarian: Buy during extreme fear, sell during extreme greed
    2. Momentum: Follow positive news cycles
    3. Combo: Buy on positive news + fear (best opportunity)
    
    Signal Logic:
    - Aggregates sentiment from recent news headlines
    - Combines with Fear & Greed Index when available
    - Generates signals based on configured mode
    """

    def __init__(self, name: str, parameters: Dict[str, Any], timeframes: List[str] = None):
        super().__init__(name, parameters, timeframes)
        
        # Strategy parameters
        self.mode = parameters.get('mode', 'contrarian')  # 'contrarian', 'momentum', 'combo'
        self.min_sentiment_score = float(parameters.get('min_sentiment_score', 0.5))
        self.fear_threshold = int(parameters.get('fear_threshold', 25))  # 0-100
        self.greed_threshold = int(parameters.get('greed_threshold', 75))  # 0-100
        self.news_lookback_hours = int(parameters.get('news_lookback_hours', 24))
        self.min_headlines = int(parameters.get('min_headlines', 5))
        
        self.news_collector = get_news_collector()
        self.config = get_config()
        
        # Simple sentiment keywords
        self.positive_keywords = [
            'surge', 'rally', 'soar', 'jump', 'gain', 'bullish', 'adoption',
            'partnership', 'etf', 'approval', 'institutional', 'buy', 'long',
            'breakout', 'record', 'high', 'upgrade', 'positive', 'growth'
        ]
        self.negative_keywords = [
            'crash', 'drop', 'plunge', 'fall', 'dump', 'bearish', 'hack',
            'scandal', 'lawsuit', 'ban', 'regulation', 'sell', 'short',
            'breakdown', 'low', 'downgrade', 'negative', 'fear', 'panic'
        ]
        
        # Cache for fear & greed
        self._fear_greed_cache: Optional[Dict[str, Any]] = None
        self._fear_greed_timestamp: Optional[datetime] = None

    def _analyze_sentiment(self, headlines: List[str]) -> float:
        """Calculate aggregate sentiment score from headlines.
        
        Returns:
            Score from -1.0 (very negative) to +1.0 (very positive)
        """
        if not headlines:
            return 0.0
        
        total_score = 0.0
        
        for headline in headlines:
            headline_lower = headline.lower()
            pos_count = sum(1 for kw in self.positive_keywords if kw in headline_lower)
            neg_count = sum(1 for kw in self.negative_keywords if kw in headline_lower)
            
            if pos_count + neg_count > 0:
                # Normalize to -1 to 1
                total_score += (pos_count - neg_count) / (pos_count + neg_count)
        
        # Average across all headlines
        return total_score / len(headlines)

    async def _fetch_fear_greed_index(self) -> Optional[int]:
        """Fetch the Fear & Greed Index from alternative.me API.
        
        Returns:
            Fear & Greed value (0-100) or None if unavailable
        """
        # Check cache (valid for 1 hour)
        if (self._fear_greed_cache and self._fear_greed_timestamp and
            (datetime.now() - self._fear_greed_timestamp).total_seconds() < 3600):
            return self._fear_greed_cache.get('value')
        
        try:
            import aiohttp
            
            url = "https://api.alternative.me/fng/"
            async with aiohttp.ClientSession() as session:
                async with session.get(url, timeout=10) as response:
                    if response.status == 200:
                        data = await response.json()
                        if data.get('data'):
                            value = int(data['data'][0]['value'])
                            self._fear_greed_cache = {'value': value}
                            self._fear_greed_timestamp = datetime.now()
                            return value
        except Exception as e:
            self.logger.debug(f"Failed to fetch Fear & Greed Index: {e}")
        
        return None

    async def on_tick(self, symbol: str, price: Decimal, timeframe: str, data: Dict[str, Any]) -> Optional[StrategySignal]:
        """Check for sentiment-based signals."""
        if not self.enabled:
            return None

        try:
            # Extract base symbol (e.g., "BTC" from "BTC/USD")
            base_symbol = symbol.split('/')[0] if '/' in symbol else symbol
            
            # Fetch news headlines
            headlines = await self.news_collector.fetch_headlines(
                symbols=[base_symbol],
                max_age_hours=self.news_lookback_hours
            )
            
            if len(headlines) < self.min_headlines:
                self.logger.debug(f"Not enough headlines: {len(headlines)} < {self.min_headlines}")
                return None
            
            # Calculate sentiment score
            sentiment = self._analyze_sentiment(headlines)
            
            # Fetch Fear & Greed Index
            fear_greed = await self._fetch_fear_greed_index()
            
            self.logger.info(
                f"Sentiment Analysis {symbol}: Score={sentiment:.2f}, "
                f"Fear&Greed={fear_greed}, Headlines={len(headlines)}"
            )
            
            signal_type = None
            description = ""
            
            if self.mode == 'contrarian':
                # Contrarian: Buy on extreme fear, sell on extreme greed
                if fear_greed is not None:
                    if fear_greed < self.fear_threshold:
                        signal_type = SignalType.BUY
                        description = f"Contrarian BUY: Extreme Fear ({fear_greed})"
                    elif fear_greed > self.greed_threshold:
                        signal_type = SignalType.SELL
                        description = f"Contrarian SELL: Extreme Greed ({fear_greed})"
            
            elif self.mode == 'momentum':
                # Momentum: Follow positive/negative sentiment
                if sentiment > self.min_sentiment_score:
                    signal_type = SignalType.BUY
                    description = f"Momentum BUY: Positive Sentiment ({sentiment:.2f})"
                elif sentiment < -self.min_sentiment_score:
                    signal_type = SignalType.SELL
                    description = f"Momentum SELL: Negative Sentiment ({sentiment:.2f})"
            
            elif self.mode == 'combo':
                # Combo: Positive news + fearful market = best buying opportunity
                if fear_greed is not None:
                    if sentiment > self.min_sentiment_score and fear_greed < 40:
                        signal_type = SignalType.BUY
                        description = f"Combo BUY: Positive News + Fear ({sentiment:.2f}, FG={fear_greed})"
                    elif sentiment < -self.min_sentiment_score and fear_greed > 60:
                        signal_type = SignalType.SELL
                        description = f"Combo SELL: Negative News + Greed ({sentiment:.2f}, FG={fear_greed})"
            
            if signal_type:
                # Calculate strength based on sentiment and fear/greed extremity
                strength = abs(sentiment)
                if fear_greed is not None:
                    fg_extremity = abs(50 - fear_greed) / 50  # How far from neutral
                    strength = (strength + fg_extremity) / 2
                
                signal = StrategySignal(
                    signal_type=signal_type,
                    symbol=symbol,
                    strength=min(1.0, strength),
                    price=price,
                    metadata={
                        "strategy": "sentiment",
                        "mode": self.mode,
                        "sentiment_score": float(sentiment),
                        "fear_greed": fear_greed,
                        "headline_count": len(headlines),
                        "sample_headlines": headlines[:3],  # Include first 3 for context
                        "description": description
                    }
                )
                self.logger.info(f"Sentiment Signal: {description}")
                return signal

        except Exception as e:
            self.logger.error(f"Error in SentimentStrategy: {e}")
            return None
            
        return None

    def on_signal(self, signal: StrategySignal) -> Optional[StrategySignal]:
        """Process signal (pass-through)."""
        return signal
