"""
Optimizer Service
Main service for content optimization with multiple entry points
"""
import logging
from typing import Optional
from igny8_core.business.content.models import Content
from igny8_core.business.optimization.models import OptimizationTask
from igny8_core.business.optimization.services.analyzer import ContentAnalyzer
from igny8_core.business.billing.services.credit_service import CreditService
from igny8_core.business.billing.exceptions import InsufficientCreditsError

logger = logging.getLogger(__name__)


class OptimizerService:
    """Service for content optimization with multiple entry points"""
    
    def __init__(self):
        self.analyzer = ContentAnalyzer()
        self.credit_service = CreditService()
    
    def optimize_from_writer(self, content_id: int) -> Content:
        """
        Entry Point 1: Writer → Optimizer
        
        Args:
            content_id: Content ID from Writer module
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id, source='igny8')
        except Content.DoesNotExist:
            raise ValueError(f"IGNY8 content with id {content_id} does not exist")
        
        return self.optimize(content)
    
    def optimize_from_wordpress_sync(self, content_id: int) -> Content:
        """
        Entry Point 2: WordPress Sync → Optimizer
        
        Args:
            content_id: Content ID synced from WordPress
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id, source='wordpress')
        except Content.DoesNotExist:
            raise ValueError(f"WordPress content with id {content_id} does not exist")
        
        return self.optimize(content)
    
    def optimize_from_external_sync(self, content_id: int) -> Content:
        """
        Entry Point 3: External Sync → Optimizer (Shopify, custom APIs)
        
        Args:
            content_id: Content ID synced from external source
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id, source__in=['shopify', 'custom'])
        except Content.DoesNotExist:
            raise ValueError(f"External content with id {content_id} does not exist")
        
        return self.optimize(content)
    
    def optimize_manual(self, content_id: int) -> Content:
        """
        Entry Point 4: Manual Selection → Optimizer
        
        Args:
            content_id: Content ID selected manually
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id)
        except Content.DoesNotExist:
            raise ValueError(f"Content with id {content_id} does not exist")
        
        return self.optimize(content)
    
    def optimize(self, content: Content) -> Content:
        """
        Unified optimization logic (used by all entry points).
        
        Args:
            content: Content instance to optimize
        
        Returns:
            Optimized Content instance
        
        Raises:
            InsufficientCreditsError: If account doesn't have enough credits
        """
        account = content.account
        word_count = content.word_count or 0
        
        # Check credits
        try:
            self.credit_service.check_credits(account, 'optimization', word_count)
        except InsufficientCreditsError:
            raise
        
        # Analyze content before optimization
        scores_before = self.analyzer.analyze(content)
        html_before = content.html_content
        
        # Create optimization task
        task = OptimizationTask.objects.create(
            content=content,
            scores_before=scores_before,
            status='running',
            html_before=html_before,
            account=account
        )
        
        try:
            # Delegate to AI function (actual optimization happens in Celery/AI task)
            # For now, we'll do a simple optimization pass
            # In production, this would call the AI function
            optimized_content = self._optimize_content(content, scores_before)
            
            # Analyze optimized content
            scores_after = self.analyzer.analyze(optimized_content)
            
            # Calculate credits used
            credits_used = self.credit_service.get_credit_cost('optimization', word_count)
            
            # Update optimization task
            task.scores_after = scores_after
            task.html_after = optimized_content.html_content
            task.status = 'completed'
            task.credits_used = credits_used
            task.save()
            
            # Update content
            content.html_content = optimized_content.html_content
            content.optimizer_version += 1
            content.optimization_scores = scores_after
            content.save(update_fields=['html_content', 'optimizer_version', 'optimization_scores'])
            
            # Deduct credits
            self.credit_service.deduct_credits_for_operation(
                account=account,
                operation_type='optimization',
                amount=word_count,
                description=f"Content optimization: {content.title or 'Untitled'}",
                related_object_type='content',
                related_object_id=content.id,
                metadata={
                    'scores_before': scores_before,
                    'scores_after': scores_after,
                    'improvement': scores_after.get('overall_score', 0) - scores_before.get('overall_score', 0)
                }
            )
            
            logger.info(f"Optimized content {content.id}: {scores_before.get('overall_score', 0)} → {scores_after.get('overall_score', 0)}")
            
            return content
            
        except Exception as e:
            logger.error(f"Error optimizing content {content.id}: {str(e)}", exc_info=True)
            task.status = 'failed'
            task.metadata = {'error': str(e)}
            task.save()
            raise
    
    def _optimize_content(self, content: Content, scores_before: dict) -> Content:
        """
        Internal method to optimize content using AI function.
        
        Args:
            content: Content to optimize
            scores_before: Scores before optimization
        
        Returns:
            Optimized Content instance
        """
        from igny8_core.ai.engine import AIEngine
        from igny8_core.ai.registry import get_function_instance
        
        # Prepare payload for AI function
        payload = {
            'ids': [content.id],
        }
        
        # Get function from registry
        fn = get_function_instance('optimize_content')
        if not fn:
            raise ValueError("OptimizeContentFunction not found in registry")
        
        # Execute AI function
        ai_engine = AIEngine(account=content.account)
        result = ai_engine.execute(fn, payload)
        
        if not result.get('success'):
            raise ValueError(f"Optimization failed: {result.get('error', 'Unknown error')}")
        
        # The AI function's save_output method already updates the content
        # We just need to refresh from database to get the updated content
        content.refresh_from_db()
        
        return content
    
    def analyze_only(self, content_id: int) -> dict:
        """
        Analyze content without optimizing (for preview).
        
        Args:
            content_id: Content ID to analyze
        
        Returns:
            Analysis scores dict
        """
        try:
            content = Content.objects.get(id=content_id)
        except Content.DoesNotExist:
            raise ValueError(f"Content with id {content_id} does not exist")
        
        return self.analyzer.analyze(content)
    
    def optimize_product(self, content_id: int) -> Content:
        """
        Optimize product content (Phase 8).
        Enhanced optimization for products: e-commerce SEO, product schema, pricing optimization.
        
        Args:
            content_id: Content ID to optimize (must be entity_type='product')
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id, entity_type='product')
        except Content.DoesNotExist:
            raise ValueError(f"Product content with id {content_id} does not exist")
        
        # Use base optimize but with product-specific enhancements
        account = content.account
        word_count = content.word_count or 0
        
        # Check credits
        try:
            self.credit_service.check_credits(account, 'optimization', word_count)
        except InsufficientCreditsError:
            raise
        
        # Analyze content before optimization
        scores_before = self.analyzer.analyze(content)
        html_before = content.html_content
        
        # Enhance scores with product-specific metrics
        scores_before = self._enhance_product_scores(scores_before, content)
        
        # Create optimization task
        task = OptimizationTask.objects.create(
            content=content,
            scores_before=scores_before,
            status='running',
            html_before=html_before,
            account=account
        )
        
        try:
            # Optimize with product-specific logic
            optimized_content = self._optimize_product_content(content, scores_before)
            
            # Analyze optimized content
            scores_after = self.analyzer.analyze(optimized_content)
            scores_after = self._enhance_product_scores(scores_after, optimized_content)
            
            # Calculate credits used
            credits_used = self.credit_service.get_credit_cost('optimization', word_count)
            
            # Update optimization task
            task.scores_after = scores_after
            task.html_after = optimized_content.html_content
            task.status = 'completed'
            task.credits_used = credits_used
            task.save()
            
            # Update content
            content.html_content = optimized_content.html_content
            content.optimizer_version += 1
            content.optimization_scores = scores_after
            content.save(update_fields=['html_content', 'optimizer_version', 'optimization_scores'])
            
            # Deduct credits
            self.credit_service.deduct_credits_for_operation(
                account=account,
                operation_type='optimization',
                amount=word_count,
                description=f"Product optimization: {content.title or 'Untitled'}",
                related_object_type='content',
                related_object_id=content.id,
                metadata={
                    'scores_before': scores_before,
                    'scores_after': scores_after,
                    'improvement': scores_after.get('overall_score', 0) - scores_before.get('overall_score', 0),
                    'entity_type': 'product'
                }
            )
            
            logger.info(f"Optimized product content {content.id}: {scores_before.get('overall_score', 0)} → {scores_after.get('overall_score', 0)}")
            
            return content
            
        except Exception as e:
            logger.error(f"Error optimizing product content {content.id}: {str(e)}", exc_info=True)
            task.status = 'failed'
            task.metadata = {'error': str(e)}
            task.save()
            raise
    
    def optimize_taxonomy(self, content_id: int) -> Content:
        """
        Optimize taxonomy content (Phase 8).
        Enhanced optimization for taxonomies: category SEO, hierarchy optimization, tag organization.
        
        Args:
            content_id: Content ID to optimize (must be entity_type='taxonomy')
        
        Returns:
            Optimized Content instance
        """
        try:
            content = Content.objects.get(id=content_id, entity_type='taxonomy')
        except Content.DoesNotExist:
            raise ValueError(f"Taxonomy content with id {content_id} does not exist")
        
        # Use base optimize but with taxonomy-specific enhancements
        account = content.account
        word_count = content.word_count or 0
        
        # Check credits
        try:
            self.credit_service.check_credits(account, 'optimization', word_count)
        except InsufficientCreditsError:
            raise
        
        # Analyze content before optimization
        scores_before = self.analyzer.analyze(content)
        html_before = content.html_content
        
        # Enhance scores with taxonomy-specific metrics
        scores_before = self._enhance_taxonomy_scores(scores_before, content)
        
        # Create optimization task
        task = OptimizationTask.objects.create(
            content=content,
            scores_before=scores_before,
            status='running',
            html_before=html_before,
            account=account
        )
        
        try:
            # Optimize with taxonomy-specific logic
            optimized_content = self._optimize_taxonomy_content(content, scores_before)
            
            # Analyze optimized content
            scores_after = self.analyzer.analyze(optimized_content)
            scores_after = self._enhance_taxonomy_scores(scores_after, optimized_content)
            
            # Calculate credits used
            credits_used = self.credit_service.get_credit_cost('optimization', word_count)
            
            # Update optimization task
            task.scores_after = scores_after
            task.html_after = optimized_content.html_content
            task.status = 'completed'
            task.credits_used = credits_used
            task.save()
            
            # Update content
            content.html_content = optimized_content.html_content
            content.optimizer_version += 1
            content.optimization_scores = scores_after
            content.save(update_fields=['html_content', 'optimizer_version', 'optimization_scores'])
            
            # Deduct credits
            self.credit_service.deduct_credits_for_operation(
                account=account,
                operation_type='optimization',
                amount=word_count,
                description=f"Taxonomy optimization: {content.title or 'Untitled'}",
                related_object_type='content',
                related_object_id=content.id,
                metadata={
                    'scores_before': scores_before,
                    'scores_after': scores_after,
                    'improvement': scores_after.get('overall_score', 0) - scores_before.get('overall_score', 0),
                    'entity_type': 'taxonomy'
                }
            )
            
            logger.info(f"Optimized taxonomy content {content.id}: {scores_before.get('overall_score', 0)} → {scores_after.get('overall_score', 0)}")
            
            return content
            
        except Exception as e:
            logger.error(f"Error optimizing taxonomy content {content.id}: {str(e)}", exc_info=True)
            task.status = 'failed'
            task.metadata = {'error': str(e)}
            task.save()
            raise
    
    def _enhance_product_scores(self, scores: dict, content: Content) -> dict:
        """Enhance scores with product-specific metrics"""
        enhanced = scores.copy()
        
        # Check for product-specific elements
        has_pricing = bool(content.structure_data.get('price_range') if content.structure_data else False)
        has_features = bool(content.json_blocks and any(b.get('type') == 'features' for b in content.json_blocks))
        has_specifications = bool(content.json_blocks and any(b.get('type') == 'specifications' for b in content.json_blocks))
        
        # Add product-specific scores
        enhanced['product_completeness'] = sum([
            1 if has_pricing else 0,
            1 if has_features else 0,
            1 if has_specifications else 0,
        ]) / 3.0
        
        return enhanced
    
    def _enhance_taxonomy_scores(self, scores: dict, content: Content) -> dict:
        """Enhance scores with taxonomy-specific metrics"""
        enhanced = scores.copy()
        
        # Check for taxonomy-specific elements
        has_categories = bool(content.json_blocks and any(b.get('type') == 'categories' for b in content.json_blocks))
        has_tags = bool(content.json_blocks and any(b.get('type') == 'tags' for b in content.json_blocks))
        has_hierarchy = bool(content.json_blocks and any(b.get('type') == 'hierarchy' for b in content.json_blocks))
        
        # Add taxonomy-specific scores
        enhanced['taxonomy_organization'] = sum([
            1 if has_categories else 0,
            1 if has_tags else 0,
            1 if has_hierarchy else 0,
        ]) / 3.0
        
        return enhanced
    
    def _optimize_product_content(self, content: Content, scores_before: dict) -> Content:
        """Optimize product content with product-specific logic"""
        # Use base optimization but enhance for products
        return self._optimize_content(content, scores_before)
    
    def _optimize_taxonomy_content(self, content: Content, scores_before: dict) -> Content:
        """Optimize taxonomy content with taxonomy-specific logic"""
        # Use base optimization but enhance for taxonomies
        return self._optimize_content(content, scores_before)


