"""
Tests for sentiment analysis worker.
"""

import pytest
from unittest.mock import Mock, patch
from sqlalchemy.orm import Session

from app.workers.sentiment_worker import (
    SentimentWorker,
    create_sentiment_worker
)


class TestSentimentWorker:
    """Tests for SentimentWorker class."""
    
    def test_initialization(self):
        """Test sentiment worker initialization."""
        worker = SentimentWorker()
        
        # No specific initialization required for sentiment worker
        assert worker is not None
    
    @patch('app.workers.sentiment_worker.process_tweet_batch')
    @patch('app.workers.sentiment_worker.get_sentiment_by_entity')
    def test_execute_sentiment_analysis_task_twitter(
        self, 
        mock_get_sentiment, 
        mock_process_batch
    ):
        """Test executing a Twitter sentiment analysis task."""
        # Create worker
        worker = SentimentWorker()
        
        # Mock database session
        mock_db = Mock(spec=Session)
        
        # Mock tweet query
        mock_tweets = [Mock()] * 100
        mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
        
        # Mock existing sentiment (none exist)
        mock_get_sentiment.return_value = None
        
        # Mock batch processing
        mock_process_batch.return_value = [Mock()] * 100
        
        # Mock calculate metrics
        with patch.object(
            worker, 
            '_calculate_sentiment_metrics', 
            return_value={
                'total_count': 100,
                'positive_count': 60,
                'negative_count': 20,
                'neutral_count': 20,
                'average_compound': 0.35
            }
        ):
            # Execute task
            task = {
                'match_id': 123,
                'source': 'twitter',
                'entity_ids': ['tweet1', 'tweet2']
            }
            
            result = worker.execute_sentiment_analysis_task(task, mock_db)
        
        # Verify result
        assert result['analyzed_count'] == 100
        assert result['status'] == 'success'
        assert result['metrics']['total_count'] == 100
        assert result['metrics']['positive_count'] == 60
    
    @patch('app.workers.sentiment_worker.process_reddit_post_batch')
    @patch('app.workers.sentiment_worker.get_sentiment_by_entity')
    def test_execute_sentiment_analysis_task_reddit(
        self,
        mock_get_sentiment,
        mock_process_batch
    ):
        """Test executing a Reddit sentiment analysis task."""
        # Create worker
        worker = SentimentWorker()
        
        # Mock database session
        mock_db = Mock(spec=Session)
        
        # Mock Reddit post query
        mock_posts = [Mock()] * 50
        mock_db.query.return_value.filter.return_value.all.return_value = mock_posts
        
        # Mock existing sentiment (none exist)
        mock_get_sentiment.return_value = None
        
        # Mock batch processing
        mock_process_batch.return_value = [Mock()] * 50
        
        # Mock calculate metrics
        with patch.object(
            worker,
            '_calculate_sentiment_metrics',
            return_value={
                'total_count': 50,
                'positive_count': 25,
                'negative_count': 15,
                'neutral_count': 10,
                'average_compound': 0.2
            }
        ):
            # Execute task
            task = {
                'match_id': 456,
                'source': 'reddit',
                'entity_ids': ['post1', 'post2']
            }
            
            result = worker.execute_sentiment_analysis_task(task, mock_db)
        
        # Verify result
        assert result['analyzed_count'] == 50
        assert result['status'] == 'success'
        assert result['metrics']['total_count'] == 50
    
    @patch('app.workers.sentiment_worker.get_sentiment_by_entity')
    def test_execute_sentiment_analysis_task_all_analyzed(
        self, 
        mock_get_sentiment
    ):
        """Test executing task when all items already analyzed."""
        worker = SentimentWorker()
        mock_db = Mock(spec=Session)
        
        # Mock tweets
        mock_tweets = [Mock()] * 100
        mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
        
        # Mock existing sentiment (all exist)
        mock_get_sentiment.return_value = Mock()
        
        # Mock calculate metrics from existing
        with patch.object(
            worker,
            '_calculate_metrics_from_existing',
            return_value={
                'total_count': 100,
                'average_compound': 0.4
            }
        ):
            # Execute task
            task = {
                'match_id': 123,
                'source': 'twitter',
                'entity_ids': ['tweet1', 'tweet2']
            }
            
            result = worker.execute_sentiment_analysis_task(task, mock_db)
        
        # Verify result (0 new items analyzed)
        assert result['analyzed_count'] == 0
        assert result['status'] == 'success'
    
    def test_execute_sentiment_analysis_task_unknown_source(self):
        """Test executing task with unknown source."""
        worker = SentimentWorker()
        mock_db = Mock(spec=Session)
        
        # Execute task with unknown source
        task = {
            'match_id': 123,
            'source': 'unknown',
            'entity_ids': ['item1']
        }
        
        result = worker.execute_sentiment_analysis_task(task, mock_db)
        
        # Verify error result
        assert result['analyzed_count'] == 0
        assert result['status'] == 'error'
        assert 'error' in result
        assert 'Unknown source' in result['error']
    
    @patch('app.workers.sentiment_worker.process_tweet_batch')
    @patch('app.workers.sentiment_worker.get_sentiment_by_entity')
    def test_execute_sentiment_analysis_task_error_handling(
        self,
        mock_get_sentiment,
        mock_process_batch
    ):
        """Test error handling in sentiment analysis."""
        worker = SentimentWorker()
        mock_db = Mock(spec=Session)
        
        # Mock tweets
        mock_tweets = [Mock()] * 10
        mock_db.query.return_value.filter.return_value.all.return_value = mock_tweets
        
        # Mock no existing sentiment
        mock_get_sentiment.return_value = None
        
        # Mock processing error
        mock_process_batch.side_effect = Exception("Processing error")
        
        # Execute task
        task = {
            'match_id': 123,
            'source': 'twitter',
            'entity_ids': ['tweet1', 'tweet2']
        }
        
        result = worker.execute_sentiment_analysis_task(task, mock_db)
        
        # Verify error handling
        assert result['analyzed_count'] == 0
        assert result['status'] == 'error'
        assert 'error' in result
    
    @patch('app.workers.sentiment_worker.get_sentiment_by_entity')
    def test_execute_twitter_sentiment_analysis_no_tweets(
        self, 
        mock_get_sentiment
    ):
        """Test Twitter sentiment analysis when no tweets found."""
        worker = SentimentWorker()
        mock_db = Mock(spec=Session)
        
        # Mock no tweets
        mock_db.query.return_value.filter.return_value.all.return_value = []
        
        # Execute task
        result = worker._execute_twitter_sentiment_analysis(
            match_id=123,
            entity_ids=['tweet1', 'tweet2'],
            db=mock_db
        )
        
        # Verify result
        assert result['analyzed_count'] == 0
        assert result['status'] == 'success'
        assert result['metrics']['total_count'] == 0


class TestCreateSentimentWorker:
    """Tests for create_sentiment_worker factory function."""
    
    def test_create_sentiment_worker(self):
        """Test creating a sentiment worker."""
        worker = create_sentiment_worker()
        
        assert isinstance(worker, SentimentWorker)
