"""
Tests for ContentPipelineService
"""
from unittest.mock import patch, MagicMock
from django.test import TestCase
from igny8_core.business.content.models import Content
from igny8_core.business.content.services.content_pipeline_service import ContentPipelineService
from igny8_core.api.tests.test_integration_base import IntegrationTestBase


class ContentPipelineServiceTests(IntegrationTestBase):
    """Tests for ContentPipelineService"""
    
    def setUp(self):
        super().setUp()
        self.service = ContentPipelineService()
        
        # Create writer content
        self.writer_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Writer Content",
            html_content="<p>Writer content.</p>",
            word_count=500,
            status='draft',
            source='igny8'
        )
        
        # Create synced content
        self.synced_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="WordPress Content",
            html_content="<p>WordPress content.</p>",
            word_count=500,
            status='draft',
            source='wordpress'
        )
    
    @patch('igny8_core.business.content.services.content_pipeline_service.LinkerService.process')
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_from_writer')
    def test_process_writer_content_full_pipeline(self, mock_optimize, mock_link):
        """Test full pipeline for writer content (linking + optimization)"""
        mock_link.return_value = self.writer_content
        mock_optimize.return_value = self.writer_content
        
        result = self.service.process_writer_content(self.writer_content.id)
        
        self.assertEqual(result.id, self.writer_content.id)
        mock_link.assert_called_once()
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_from_writer')
    def test_process_writer_content_optimization_only(self, mock_optimize):
        """Test writer content with optimization only"""
        mock_optimize.return_value = self.writer_content
        
        result = self.service.process_writer_content(
            self.writer_content.id,
            stages=['optimization']
        )
        
        self.assertEqual(result.id, self.writer_content.id)
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.LinkerService.process')
    def test_process_writer_content_linking_only(self, mock_link):
        """Test writer content with linking only"""
        mock_link.return_value = self.writer_content
        
        result = self.service.process_writer_content(
            self.writer_content.id,
            stages=['linking']
        )
        
        self.assertEqual(result.id, self.writer_content.id)
        mock_link.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.LinkerService.process')
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_from_writer')
    def test_process_writer_content_handles_linker_failure(self, mock_optimize, mock_link):
        """Test that pipeline continues when linking fails"""
        mock_link.side_effect = Exception("Linking failed")
        mock_optimize.return_value = self.writer_content
        
        # Should not raise exception, should continue to optimization
        result = self.service.process_writer_content(self.writer_content.id)
        
        self.assertEqual(result.id, self.writer_content.id)
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_from_wordpress_sync')
    def test_process_synced_content_wordpress(self, mock_optimize):
        """Test synced content pipeline for WordPress"""
        mock_optimize.return_value = self.synced_content
        
        result = self.service.process_synced_content(self.synced_content.id)
        
        self.assertEqual(result.id, self.synced_content.id)
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_from_external_sync')
    def test_process_synced_content_shopify(self, mock_optimize):
        """Test synced content pipeline for Shopify"""
        shopify_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Shopify Content",
            word_count=100,
            source='shopify'
        )
        mock_optimize.return_value = shopify_content
        
        result = self.service.process_synced_content(shopify_content.id)
        
        self.assertEqual(result.id, shopify_content.id)
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.OptimizerService.optimize_manual')
    def test_process_synced_content_custom(self, mock_optimize):
        """Test synced content pipeline for custom source"""
        custom_content = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Custom Content",
            word_count=100,
            source='custom'
        )
        mock_optimize.return_value = custom_content
        
        result = self.service.process_synced_content(custom_content.id)
        
        self.assertEqual(result.id, custom_content.id)
        mock_optimize.assert_called_once()
    
    @patch('igny8_core.business.content.services.content_pipeline_service.ContentPipelineService.process_writer_content')
    def test_batch_process_writer_content(self, mock_process):
        """Test batch processing writer content"""
        content2 = Content.objects.create(
            account=self.account,
            site=self.site,
            sector=self.sector,
            title="Content 2",
            word_count=100,
            source='igny8'
        )
        
        mock_process.side_effect = [self.writer_content, content2]
        
        results = self.service.batch_process_writer_content([
            self.writer_content.id,
            content2.id
        ])
        
        self.assertEqual(len(results), 2)
        self.assertEqual(mock_process.call_count, 2)
    
    @patch('igny8_core.business.content.services.content_pipeline_service.ContentPipelineService.process_writer_content')
    def test_batch_process_handles_partial_failure(self, mock_process):
        """Test batch processing handles partial failures"""
        mock_process.side_effect = [self.writer_content, Exception("Failed")]
        
        results = self.service.batch_process_writer_content([
            self.writer_content.id,
            99999
        ])
        
        # Should continue processing and return successful results
        self.assertEqual(len(results), 1)
        self.assertEqual(results[0].id, self.writer_content.id)
    
    def test_process_writer_content_invalid_content(self):
        """Test that ValueError is raised for invalid content"""
        with self.assertRaises(ValueError):
            self.service.process_writer_content(99999)
    
    def test_process_synced_content_invalid_content(self):
        """Test that ValueError is raised for invalid synced content"""
        with self.assertRaises(ValueError):
            self.service.process_synced_content(99999)

