"""
Tests for OptimizerService
"""
from unittest.mock import Mock, patch, MagicMock
from django.test import TestCase
from igny8_core.business.content.models import Content
from igny8_core.business.optimization.models import OptimizationTask
from igny8_core.business.optimization.services.optimizer_service import OptimizerService
from igny8_core.business.billing.exceptions import InsufficientCreditsError
from igny8_core.api.tests.test_integration_base import IntegrationTestBase


class OptimizerServiceTests(IntegrationTestBase):
    """Tests for OptimizerService"""
    
    def setUp(self):
        super().setUp()
        self.service = OptimizerService()
        
        # Create test content
        self.content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Test Content",
            html_content="<p>This is test content.</p>",
            meta_title="Test Title",
            meta_description="Test description",
            primary_keyword="test keyword",
            word_count=500,
            status='draft',
            source='igny8'
        )
    
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.check_credits')
    @patch('igny8_core.business.optimization.services.optimizer_service.ContentAnalyzer.analyze')
    @patch('igny8_core.business.optimization.services.optimizer_service.OptimizerService._optimize_content')
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.deduct_credits_for_operation')
    def test_optimize_from_writer(self, mock_deduct, mock_optimize, mock_analyze, mock_check):
        """Test optimize_from_writer entry point"""
        mock_check.return_value = True
        mock_analyze.return_value = {
            'seo_score': 50.0,
            'readability_score': 60.0,
            'engagement_score': 55.0,
            'overall_score': 55.0
        }
        
        optimized_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Optimized Content",
            html_content="<p>Optimized content.</p>",
            word_count=500,
            status='draft',
            source='igny8'
        )
        mock_optimize.return_value = optimized_content
        
        result = self.service.optimize_from_writer(self.content.id)
        
        self.assertEqual(result.id, self.content.id)
        mock_check.assert_called_once()
        mock_deduct.assert_called_once()
    
    def test_optimize_from_writer_invalid_content(self):
        """Test that ValueError is raised for invalid content"""
        with self.assertRaises(ValueError):
            self.service.optimize_from_writer(99999)
    
    def test_optimize_from_writer_wrong_source(self):
        """Test that ValueError is raised for wrong source"""
        content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="WordPress Content",
            word_count=100,
            source='wordpress'
        )
        
        with self.assertRaises(ValueError):
            self.service.optimize_from_writer(content.id)
    
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.check_credits')
    def test_optimize_insufficient_credits(self, mock_check):
        """Test that InsufficientCreditsError is raised when credits are insufficient"""
        mock_check.side_effect = InsufficientCreditsError("Insufficient credits")
        
        with self.assertRaises(InsufficientCreditsError):
            self.service.optimize(self.content)
    
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.check_credits')
    @patch('igny8_core.business.optimization.services.optimizer_service.ContentAnalyzer.analyze')
    @patch('igny8_core.business.optimization.services.optimizer_service.OptimizerService._optimize_content')
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.deduct_credits_for_operation')
    def test_optimize_creates_optimization_task(self, mock_deduct, mock_optimize, mock_analyze, mock_check):
        """Test that optimization creates OptimizationTask"""
        mock_check.return_value = True
        scores = {
            'seo_score': 50.0,
            'readability_score': 60.0,
            'engagement_score': 55.0,
            'overall_score': 55.0
        }
        mock_analyze.return_value = scores
        
        optimized_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Optimized",
            html_content="<p>Optimized.</p>",
            word_count=500,
            status='draft'
        )
        mock_optimize.return_value = optimized_content
        
        result = self.service.optimize(self.content)
        
        # Check that task was created
        task = OptimizationTask.objects.filter(content=self.content).first()
        self.assertIsNotNone(task)
        self.assertEqual(task.status, 'completed')
        self.assertEqual(task.scores_before, scores)
    
    @patch('igny8_core.business.optimization.services.optimizer_service.CreditService.check_credits')
    @patch('igny8_core.business.optimization.services.optimizer_service.ContentAnalyzer.analyze')
    def test_analyze_only_returns_scores(self, mock_analyze, mock_check):
        """Test analyze_only method returns scores without optimizing"""
        scores = {
            'seo_score': 50.0,
            'readability_score': 60.0,
            'engagement_score': 55.0,
            'overall_score': 55.0
        }
        mock_analyze.return_value = scores
        
        result = self.service.analyze_only(self.content.id)
        
        self.assertEqual(result, scores)
        mock_analyze.assert_called_once()
    
    def test_optimize_from_wordpress_sync(self):
        """Test optimize_from_wordpress_sync entry point"""
        content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="WordPress Content",
            word_count=100,
            source='wordpress'
        )
        
        with patch.object(self.service, 'optimize') as mock_optimize:
            mock_optimize.return_value = content
            result = self.service.optimize_from_wordpress_sync(content.id)
            
            self.assertEqual(result.id, content.id)
            mock_optimize.assert_called_once()
    
    def test_optimize_from_external_sync(self):
        """Test optimize_from_external_sync entry point"""
        content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Shopify Content",
            word_count=100,
            source='shopify'
        )
        
        with patch.object(self.service, 'optimize') as mock_optimize:
            mock_optimize.return_value = content
            result = self.service.optimize_from_external_sync(content.id)
            
            self.assertEqual(result.id, content.id)
            mock_optimize.assert_called_once()
    
    def test_optimize_manual(self):
        """Test optimize_manual entry point"""
        with patch.object(self.service, 'optimize') as mock_optimize:
            mock_optimize.return_value = self.content
            result = self.service.optimize_manual(self.content.id)
            
            self.assertEqual(result.id, self.content.id)
            mock_optimize.assert_called_once()

