"""Sentiment analysis provider using transformers or simple heuristics."""
import asyncio
from typing import Optional
from .base import BaseProvider, OracleData


class SentimentProvider(BaseProvider):
    """Sentiment analysis oracle provider.

    Uses HuggingFace transformers for ML-based sentiment,
    or falls back to simple keyword-based analysis.
    """

    name = "sentiment"

    def __init__(self, use_ml: bool = True):
        self.use_ml = use_ml
        self._model = None
        self._tokenizer = None

    def _load_model(self):
        """Lazy load the sentiment model."""
        if self._model is not None:
            return

        if self.use_ml:
            try:
                from transformers import pipeline
                self._model = pipeline(
                    "sentiment-analysis",
                    model="distilbert-base-uncased-finetuned-sst-2-english",
                )
            except ImportError:
                print("[Warning] transformers not installed, using simple sentiment")
                self.use_ml = False

    def _simple_sentiment(self, text: str) -> tuple[str, float]:
        """Simple keyword-based sentiment analysis."""
        text_lower = text.lower()

        positive_words = {
            "good", "great", "excellent", "amazing", "wonderful", "fantastic",
            "love", "best", "happy", "bullish", "moon", "pump", "buy", "long",
            "profit", "gain", "up", "rise", "grow", "success", "win",
        }
        negative_words = {
            "bad", "terrible", "awful", "horrible", "hate", "worst",
            "bearish", "dump", "sell", "short", "loss", "down", "fall",
            "crash", "fail", "scam", "rug", "dead",
        }

        words = set(text_lower.split())
        pos_count = len(words & positive_words)
        neg_count = len(words & negative_words)

        total = pos_count + neg_count
        if total == 0:
            return "NEUTRAL", 0.5

        if pos_count > neg_count:
            confidence = pos_count / (total + 1)  # +1 to avoid overconfidence
            return "POSITIVE", min(0.95, 0.5 + confidence * 0.5)
        elif neg_count > pos_count:
            confidence = neg_count / (total + 1)
            return "NEGATIVE", min(0.95, 0.5 + confidence * 0.5)
        else:
            return "NEUTRAL", 0.5

    async def fetch(self, key: str, text: Optional[str] = None, **kwargs) -> OracleData:
        """Analyze sentiment of text.

        Args:
            key: Identifier for this analysis (e.g., "twitter:nanopy")
            text: Text to analyze. If None, will try to fetch from source.
            **kwargs: Additional arguments

        Returns:
            OracleData with sentiment result
        """
        if text is None:
            # In a real implementation, fetch from Twitter/Discord/etc.
            text = kwargs.get("default_text", "No text provided")

        self._load_model()

        if self.use_ml and self._model:
            # Run in thread pool to not block async
            loop = asyncio.get_event_loop()
            result = await loop.run_in_executor(None, self._model, text)
            label = result[0]["label"]
            score = result[0]["score"]
        else:
            label, score = self._simple_sentiment(text)

        # Convert to numeric value for on-chain storage
        # POSITIVE = 1, NEUTRAL = 0, NEGATIVE = -1
        value_map = {"POSITIVE": 1, "NEUTRAL": 0, "NEGATIVE": -1}
        numeric_value = value_map.get(label.upper(), 0)

        return self.create_data(
            key=key,
            value=numeric_value,
            confidence=score,
            metadata={
                "label": label,
                "text_length": len(text),
                "method": "ml" if self.use_ml else "heuristic",
            },
        )

    async def validate(self, data: OracleData) -> bool:
        """Validate sentiment data."""
        if data.value not in [-1, 0, 1]:
            return False
        if not 0.0 <= data.confidence <= 1.0:
            return False
        return True


class BatchSentimentProvider(SentimentProvider):
    """Batch sentiment analysis for multiple texts."""

    name = "sentiment_batch"

    async def fetch_batch(self, key: str, texts: list[str]) -> OracleData:
        """Analyze sentiment of multiple texts and aggregate."""
        if not texts:
            return self.create_data(key=key, value=0, confidence=0.0)

        results = []
        for text in texts:
            data = await self.fetch(f"{key}:item", text=text)
            results.append(data.value)

        # Aggregate: average sentiment
        avg_sentiment = sum(results) / len(results)

        # Round to -1, 0, or 1
        if avg_sentiment > 0.33:
            final_value = 1
        elif avg_sentiment < -0.33:
            final_value = -1
        else:
            final_value = 0

        # Confidence based on agreement
        agreement = sum(1 for r in results if r == final_value) / len(results)

        return self.create_data(
            key=key,
            value=final_value,
            confidence=agreement,
            metadata={
                "sample_size": len(texts),
                "raw_average": avg_sentiment,
                "agreement": agreement,
            },
        )
