"""SentimentAnalyst implementation for OpenClaw trading system.

This module provides the SentimentAnalyst class that analyzes market sentiment
by collecting and analyzing news data to generate sentiment reports.
"""

from __future__ import annotations

import random
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List, Optional

from openclaw.agents.base import ActivityType, BaseAgent
from openclaw.core.economy import SurvivalStatus


@dataclass
class SentimentSource:
    """A single sentiment source (news article, tweet, etc.)."""

    title: str
    content: str
    source: str
    timestamp: str
    raw_sentiment: str = ""  # "positive", "negative", "neutral"
    relevance_score: float = 0.5  # 0.0 to 1.0


@dataclass
class SentimentReport:
    """Sentiment analysis report for a symbol."""

    symbol: str
    overall_sentiment: str  # "bullish", "bearish", "neutral"
    sentiment_score: float  # -1.0 to 1.0
    sources: List[SentimentSource]
    summary: str
    timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
    confidence: float = 0.5  # 0.0 to 1.0
    sample_headlines: List[str] = field(default_factory=list)


class SentimentAnalyst(BaseAgent):
    """Agent that analyzes market sentiment from news and social data.

    The SentimentAnalyst collects news data, performs sentiment analysis
    using keyword-based and rule-based approaches, and generates
    comprehensive sentiment reports for trading symbols.

    Args:
        agent_id: Unique identifier for this agent
        initial_capital: Starting balance for the agent
        skill_level: Initial skill level (0.0 to 1.0)
        max_sources: Maximum number of sources to analyze per symbol
    """

    decision_cost = 0.08

    # Sentiment keywords for analysis
    BULLISH_KEYWORDS = [
        "surge", "rally", "gain", "growth", "profit", "beat", "strong",
        "bullish", "upgrade", "outperform", "breakthrough", "record",
        "soar", "jump", "rocket", "boom", "positive", "optimistic",
        "expansion", "partnership", "innovation", "success", "milestone"
    ]

    BEARISH_KEYWORDS = [
        "crash", "plunge", "drop", "decline", "loss", "miss", "weak",
        "bearish", "downgrade", "underperform", "crisis", "concern",
        "fall", "tumble", "slump", "recession", "negative", "pessimistic",
        "layoff", "lawsuit", "investigation", "debt", "bankruptcy"
    ]

    def __init__(
        self,
        agent_id: str,
        initial_capital: float,
        skill_level: float = 0.5,
        max_sources: int = 10,
    ):
        super().__init__(agent_id, initial_capital, skill_level)
        self.max_sources = max_sources
        self._analysis_history: List[SentimentReport] = []

    async def decide_activity(self) -> ActivityType:
        """Decide what activity to perform based on economic status.

        Returns:
            The activity type to perform
        """
        status = self.survival_status

        # Bankrupt agents can only rest
        if status == SurvivalStatus.BANKRUPT:
            self.logger.warning("Agent is bankrupt, resting...")
            return ActivityType.REST

        # Critical status - focus on learning
        if status == SurvivalStatus.CRITICAL:
            if self.skill_level < 0.7:
                return ActivityType.LEARN
            return ActivityType.PAPER_TRADE

        # Struggling - more paper trading, less real analysis
        if status == SurvivalStatus.STRUGGLING:
            if random.random() < 0.5:
                return ActivityType.PAPER_TRADE
            if self.skill_level < 0.6:
                return ActivityType.LEARN
            return ActivityType.ANALYZE

        # Stable and thriving - can analyze more
        if status in [SurvivalStatus.STABLE, SurvivalStatus.THRIVING]:
            if random.random() < 0.2:
                return ActivityType.PAPER_TRADE
            return ActivityType.ANALYZE

        # Default to analyze
        return ActivityType.ANALYZE

    async def analyze(self, symbol: str) -> Dict[str, Any]:
        """Analyze a trading symbol and return sentiment analysis.

        This method performs sentiment analysis and generates a sentiment report.

        Args:
            symbol: The symbol to analyze (e.g., "AAPL")

        Returns:
            Dictionary containing sentiment analysis results
        """
        # Deduct decision cost for analysis
        cost = self.economic_tracker.calculate_decision_cost(
            tokens_input=300,
            tokens_output=150,
            market_data_calls=1,
        )
        self.logger.info(f"Sentiment analysis cost for {symbol}: ${cost:.4f}")

        # Perform sentiment analysis
        report = await self.analyze_sentiment(symbol)

        return {
            "symbol": symbol,
            "sentiment": report.overall_sentiment,
            "score": report.sentiment_score,
            "confidence": report.confidence,
            "summary": report.summary,
            "sources_analyzed": len(report.sources),
            "cost": cost,
        }

    async def analyze_sentiment(self, symbol: str) -> SentimentReport:
        """Analyze market sentiment for a symbol.

        This method collects news data and performs sentiment analysis
        to generate a comprehensive sentiment report.

        Args:
            symbol: The symbol to analyze (e.g., "AAPL")

        Returns:
            SentimentReport with analysis results
        """
        # Deduct the fixed decision cost
        self.economic_tracker._update_balance(
            -self.decision_cost,
            f"Sentiment analysis decision cost for {symbol}"
        )
        self.logger.info(
            f"Deducted ${self.decision_cost:.2f} for sentiment analysis of {symbol}"
        )

        # Collect news data (simulated)
        sources = self._collect_news_data(symbol)

        # Analyze sentiment from sources
        sentiment_score, confidence = self._calculate_sentiment(sources)

        # Determine overall sentiment
        if sentiment_score > 0.2:
            overall_sentiment = "bullish"
        elif sentiment_score < -0.2:
            overall_sentiment = "bearish"
        else:
            overall_sentiment = "neutral"

        # Generate summary
        summary = self._generate_summary(symbol, overall_sentiment, sentiment_score, sources)

        # Get sample headlines
        sample_headlines = [s.title for s in sources[:3]]

        # Create report
        report = SentimentReport(
            symbol=symbol,
            overall_sentiment=overall_sentiment,
            sentiment_score=round(sentiment_score, 4),
            sources=sources,
            summary=summary,
            confidence=round(confidence, 4),
            sample_headlines=sample_headlines,
        )

        self._analysis_history.append(report)

        self.logger.info(
            f"Sentiment analysis for {symbol}: {overall_sentiment} "
            f"(score: {sentiment_score:.2f}, confidence: {confidence:.2f})"
        )

        return report

    def _collect_news_data(self, symbol: str) -> List[SentimentSource]:
        """Collect news data for sentiment analysis (simulated).

        In production, this would fetch real news from APIs.
        For now, we simulate news based on the symbol.

        Args:
            symbol: The symbol to collect news for

        Returns:
            List of SentimentSource objects
        """
        # Seed random for reproducibility based on symbol
        random.seed(hash(symbol + datetime.now().strftime("%Y%m%d")))

        sources = []

        # Generate simulated news headlines
        bullish_templates = [
            f"{symbol} Reports Record Quarterly Earnings, Beats Expectations",
            f"{symbol} Announces Major Partnership Deal",
            f"{symbol} Stock Surges on Strong Revenue Growth",
            f"Analysts Upgrade {symbol} to Strong Buy",
            f"{symbol} Expands into New Markets with Innovative Products",
        ]

        bearish_templates = [
            f"{symbol} Misses Earnings Estimates, Stock Plunges",
            f"{symbol} Faces Regulatory Investigation",
            f"{symbol} Announces Layoffs Amid Market Challenges",
            f"Analysts Downgrade {symbol} to Sell",
            f"{symbol} Revenue Declines for Third Consecutive Quarter",
        ]

        neutral_templates = [
            f"{symbol} Reports Mixed Results in Latest Quarter",
            f"{symbol} Announces Regular Dividend Payment",
            f"{symbol} Management Discusses Future Strategy",
            f"Market Awaits {symbol} Next Product Launch",
            f"{symbol} Stock Trades Sideways in Volatile Market",
        ]

        # Determine bias based on skill level (higher skill = more accurate)
        accuracy_factor = self.skill_level

        # Generate sources with some randomness
        num_sources = min(self.max_sources, 5 + int(random.random() * 5))

        for i in range(num_sources):
            # Higher skill = more consistent sentiment direction
            if accuracy_factor > 0.7:
                # High skill: more consistent, realistic news
                if random.random() < 0.6:
                    template = random.choice(bullish_templates)
                    raw_sentiment = "positive"
                elif random.random() < 0.5:
                    template = random.choice(bearish_templates)
                    raw_sentiment = "negative"
                else:
                    template = random.choice(neutral_templates)
                    raw_sentiment = "neutral"
            else:
                # Lower skill: more random, mixed news
                r = random.random()
                if r < 0.33:
                    template = random.choice(bullish_templates)
                    raw_sentiment = "positive"
                elif r < 0.66:
                    template = random.choice(bearish_templates)
                    raw_sentiment = "negative"
                else:
                    template = random.choice(neutral_templates)
                    raw_sentiment = "neutral"

            source = SentimentSource(
                title=template,
                content=f"Detailed article about {symbol}...",
                source=random.choice(["Reuters", "Bloomberg", "CNBC", "WSJ", "TechCrunch"]),
                timestamp=datetime.now().isoformat(),
                raw_sentiment=raw_sentiment,
                relevance_score=round(0.5 + random.random() * 0.5, 2),
            )
            sources.append(source)

        # Reset random seed
        random.seed()

        return sources

    def _calculate_sentiment(self, sources: List[SentimentSource]) -> tuple[float, float]:
        """Calculate sentiment score from sources.

        Args:
            sources: List of sentiment sources to analyze

        Returns:
            Tuple of (sentiment_score, confidence)
        """
        if not sources:
            return 0.0, 0.0

        total_score = 0.0
        total_weight = 0.0

        for source in sources:
            # Analyze content for keywords
            content = f"{source.title} {source.content}".lower()

            bullish_count = sum(1 for kw in self.BULLISH_KEYWORDS if kw in content)
            bearish_count = sum(1 for kw in self.BEARISH_KEYWORDS if kw in content)

            # Calculate raw sentiment for this source
            if bullish_count + bearish_count > 0:
                source_score = (bullish_count - bearish_count) / (bullish_count + bearish_count)
            else:
                source_score = 0.0

            # Weight by relevance
            weight = source.relevance_score
            total_score += source_score * weight
            total_weight += weight

        if total_weight > 0:
            sentiment_score = total_score / total_weight
        else:
            sentiment_score = 0.0

        # Calculate confidence based on:
        # 1. Number of sources
        # 2. Skill level
        # 3. Sentiment clarity (how far from neutral)
        source_confidence = min(len(sources) / 10, 1.0)  # More sources = higher confidence
        skill_confidence = self.skill_level
        clarity_confidence = abs(sentiment_score)  # Stronger sentiment = higher confidence

        confidence = (source_confidence * 0.3 + skill_confidence * 0.4 + clarity_confidence * 0.3)

        # Clamp confidence
        confidence = max(0.1, min(1.0, confidence))

        return sentiment_score, confidence

    def _generate_summary(
        self,
        symbol: str,
        sentiment: str,
        score: float,
        sources: List[SentimentSource],
    ) -> str:
        """Generate a summary of the sentiment analysis.

        Args:
            symbol: The analyzed symbol
            sentiment: Overall sentiment (bullish/bearish/neutral)
            score: Sentiment score
            sources: List of sources analyzed

        Returns:
            Summary string
        """
        positive_count = sum(1 for s in sources if s.raw_sentiment == "positive")
        negative_count = sum(1 for s in sources if s.raw_sentiment == "negative")
        neutral_count = len(sources) - positive_count - negative_count

        if sentiment == "bullish":
            summary = (
                f"{symbol} shows bullish sentiment with {positive_count} positive, "
                f"{negative_count} negative, and {neutral_count} neutral sources. "
                f"Sentiment score of {score:.2f} indicates optimistic market outlook."
            )
        elif sentiment == "bearish":
            summary = (
                f"{symbol} shows bearish sentiment with {positive_count} positive, "
                f"{negative_count} negative, and {neutral_count} neutral sources. "
                f"Sentiment score of {score:.2f} suggests cautious market outlook."
            )
        else:
            summary = (
                f"{symbol} shows neutral sentiment with {positive_count} positive, "
                f"{negative_count} negative, and {neutral_count} neutral sources. "
                f"Sentiment score of {score:.2f} indicates mixed market signals."
            )

        return summary

    def get_analysis_history(self) -> List[SentimentReport]:
        """Get history of sentiment analyses."""
        return self._analysis_history.copy()

    def get_sentiment_trend(self, symbol: str, limit: int = 5) -> Optional[Dict[str, Any]]:
        """Get sentiment trend for a symbol from analysis history.

        Args:
            symbol: The symbol to get trend for
            limit: Maximum number of recent analyses to include

        Returns:
            Dictionary with trend data or None if no history
        """
        symbol_analyses = [
            a for a in self._analysis_history if a.symbol == symbol
        ][-limit:]

        if not symbol_analyses:
            return None

        scores = [a.sentiment_score for a in symbol_analyses]
        avg_score = sum(scores) / len(scores)

        # Determine trend direction
        if len(scores) >= 2:
            recent_avg = sum(scores[-2:]) / 2
            older_avg = sum(scores[:-2]) / max(len(scores) - 2, 1)

            if recent_avg > older_avg + 0.1:
                trend = "improving"
            elif recent_avg < older_avg - 0.1:
                trend = "deteriorating"
            else:
                trend = "stable"
        else:
            trend = "insufficient_data"

        return {
            "symbol": symbol,
            "average_score": round(avg_score, 4),
            "trend": trend,
            "analyses_count": len(symbol_analyses),
            "latest_sentiment": symbol_analyses[-1].overall_sentiment,
        }
