"""
Outline Generator - AI-powered outline generation from research data.

Generates comprehensive, SEO-optimized outlines using research intelligence.
"""

from typing import Dict, Any, List, Tuple
import asyncio
from loguru import logger

from models.blog_models import (
    BlogOutlineRequest,
    BlogOutlineResponse,
    BlogOutlineSection,
)

from .source_mapper import SourceToSectionMapper
from .section_enhancer import SectionEnhancer
from .outline_optimizer import OutlineOptimizer
from .grounding_engine import GroundingContextEngine
from .title_generator import TitleGenerator
from .metadata_collector import MetadataCollector
from .prompt_builder import PromptBuilder
from .response_processor import ResponseProcessor
from .parallel_processor import ParallelProcessor


class OutlineGenerator:
    """Generates AI-powered outlines from research data."""
    
    def __init__(self):
        """Initialize the outline generator with all enhancement modules."""
        self.source_mapper = SourceToSectionMapper()
        self.section_enhancer = SectionEnhancer()
        self.outline_optimizer = OutlineOptimizer()
        self.grounding_engine = GroundingContextEngine()
        
        # Initialize extracted classes
        self.title_generator = TitleGenerator()
        self.metadata_collector = MetadataCollector()
        self.prompt_builder = PromptBuilder()
        self.response_processor = ResponseProcessor()
        self.parallel_processor = ParallelProcessor(self.source_mapper, self.grounding_engine)
    
    async def generate(self, request: BlogOutlineRequest, user_id: str) -> BlogOutlineResponse:
        """
        Generate AI-powered outline using research results.
        
        Args:
            request: Outline generation request with research data
            user_id: User ID (required for subscription checks and usage tracking)
            
        Raises:
            ValueError: If user_id is not provided
        """
        if not user_id:
            raise ValueError("user_id is required for outline generation (subscription checks and usage tracking)")
        
        # Extract research insights
        research = request.research
        primary_keywords = research.keyword_analysis.get('primary', [])
        secondary_keywords = research.keyword_analysis.get('secondary', [])
        content_angles = research.suggested_angles
        sources = research.sources
        search_intent = research.keyword_analysis.get('search_intent', 'informational')
        
        # Check for custom instructions
        custom_instructions = getattr(request, 'custom_instructions', None)
        
        # Build comprehensive outline generation prompt with rich research data
        outline_prompt = self.prompt_builder.build_outline_prompt(
            primary_keywords, secondary_keywords, content_angles, sources,
            search_intent, request, custom_instructions
        )
        
        logger.info("Generating AI-powered outline using research results")
        
        # Define schema with proper property ordering (critical for Gemini API)
        outline_schema = self.prompt_builder.get_outline_schema()
        
        # Generate outline using structured JSON response with retry logic (user_id required)
        outline_data = await self.response_processor.generate_with_retry(outline_prompt, outline_schema, user_id)
        
        # Convert to BlogOutlineSection objects
        outline_sections = self.response_processor.convert_to_sections(outline_data, sources)
        
        # Run parallel processing for speed optimization (user_id required)
        mapped_sections, grounding_insights = await self.parallel_processor.run_parallel_processing_async(
            outline_sections, research, user_id
        )
        
        # Enhance sections with grounding insights
        logger.info("Enhancing sections with grounding insights...")
        grounding_enhanced_sections = self.grounding_engine.enhance_sections_with_grounding(
            mapped_sections, research.grounding_metadata, grounding_insights
        )
        
        # Optimize outline for better flow, SEO, and engagement (user_id required)
        logger.info("Optimizing outline for better flow and engagement...")
        optimized_sections = await self.outline_optimizer.optimize(grounding_enhanced_sections, "comprehensive optimization", user_id)
        
        # Rebalance word counts for optimal distribution
        target_words = request.word_count or 1500
        balanced_sections = self.outline_optimizer.rebalance_word_counts(optimized_sections, target_words)
        
        # Extract title options - combine AI-generated with content angles
        ai_title_options = outline_data.get('title_options', [])
        content_angle_titles = self.title_generator.extract_content_angle_titles(research)
        
        # Combine AI-generated titles with content angles
        title_options = self.title_generator.combine_title_options(ai_title_options, content_angle_titles, primary_keywords)
        
        logger.info(f"Generated optimized outline with {len(balanced_sections)} sections and {len(title_options)} title options")
        
        # Collect metadata for enhanced UI
        source_mapping_stats = self.metadata_collector.collect_source_mapping_stats(mapped_sections, research)
        grounding_insights_data = self.metadata_collector.collect_grounding_insights(grounding_insights)
        optimization_results = self.metadata_collector.collect_optimization_results(optimized_sections, "comprehensive optimization")
        research_coverage = self.metadata_collector.collect_research_coverage(research)
        
        return BlogOutlineResponse(
            success=True,
            title_options=title_options,
            outline=balanced_sections,
            source_mapping_stats=source_mapping_stats,
            grounding_insights=grounding_insights_data,
            optimization_results=optimization_results,
            research_coverage=research_coverage
        )
    
    async def generate_with_progress(self, request: BlogOutlineRequest, task_id: str, user_id: str) -> BlogOutlineResponse:
        """
        Outline generation method with progress updates for real-time feedback.
        
        Args:
            request: Outline generation request with research data
            task_id: Task ID for progress updates
            user_id: User ID (required for subscription checks and usage tracking)
            
        Raises:
            ValueError: If user_id is not provided
        """
        if not user_id:
            raise ValueError("user_id is required for outline generation (subscription checks and usage tracking)")
        
        from api.blog_writer.task_manager import task_manager
        
        # Extract research insights
        research = request.research
        primary_keywords = research.keyword_analysis.get('primary', [])
        secondary_keywords = research.keyword_analysis.get('secondary', [])
        content_angles = research.suggested_angles
        sources = research.sources
        search_intent = research.keyword_analysis.get('search_intent', 'informational')
        
        # Check for custom instructions
        custom_instructions = getattr(request, 'custom_instructions', None)
        
        await task_manager.update_progress(task_id, "📊 Analyzing research data and building content strategy...")
        
        # Build comprehensive outline generation prompt with rich research data
        outline_prompt = self.prompt_builder.build_outline_prompt(
            primary_keywords, secondary_keywords, content_angles, sources,
            search_intent, request, custom_instructions
        )
        
        await task_manager.update_progress(task_id, "🤖 Generating AI-powered outline with research insights...")
        
        # Define schema with proper property ordering (critical for Gemini API)
        outline_schema = self.prompt_builder.get_outline_schema()
        
        await task_manager.update_progress(task_id, "🔄 Making AI request to generate structured outline...")
        
        # Generate outline using structured JSON response with retry logic (user_id required for subscription checks)
        outline_data = await self.response_processor.generate_with_retry(outline_prompt, outline_schema, user_id, task_id)
        
        await task_manager.update_progress(task_id, "📝 Processing outline structure and validating sections...")
        
        # Convert to BlogOutlineSection objects
        outline_sections = self.response_processor.convert_to_sections(outline_data, sources)
        
        # Run parallel processing for speed optimization (user_id required for subscription checks)
        mapped_sections, grounding_insights = await self.parallel_processor.run_parallel_processing(
            outline_sections, research, user_id, task_id
        )
        
        # Enhance sections with grounding insights (depends on both previous tasks)
        await task_manager.update_progress(task_id, "✨ Enhancing sections with grounding insights...")
        grounding_enhanced_sections = self.grounding_engine.enhance_sections_with_grounding(
            mapped_sections, research.grounding_metadata, grounding_insights
        )
        
        # Optimize outline for better flow, SEO, and engagement (user_id required for subscription checks)
        await task_manager.update_progress(task_id, "🎯 Optimizing outline for better flow and engagement...")
        optimized_sections = await self.outline_optimizer.optimize(grounding_enhanced_sections, "comprehensive optimization", user_id)
        
        # Rebalance word counts for optimal distribution
        await task_manager.update_progress(task_id, "⚖️ Rebalancing word count distribution...")
        target_words = request.word_count or 1500
        balanced_sections = self.outline_optimizer.rebalance_word_counts(optimized_sections, target_words)
        
        # Extract title options - combine AI-generated with content angles
        ai_title_options = outline_data.get('title_options', [])
        content_angle_titles = self.title_generator.extract_content_angle_titles(research)
        
        # Combine AI-generated titles with content angles
        title_options = self.title_generator.combine_title_options(ai_title_options, content_angle_titles, primary_keywords)
        
        await task_manager.update_progress(task_id, "✅ Outline generation and optimization completed successfully!")
        
        # Collect metadata for enhanced UI
        source_mapping_stats = self.metadata_collector.collect_source_mapping_stats(mapped_sections, research)
        grounding_insights_data = self.metadata_collector.collect_grounding_insights(grounding_insights)
        optimization_results = self.metadata_collector.collect_optimization_results(optimized_sections, "comprehensive optimization")
        research_coverage = self.metadata_collector.collect_research_coverage(research)
        
        return BlogOutlineResponse(
            success=True,
            title_options=title_options,
            outline=balanced_sections,
            source_mapping_stats=source_mapping_stats,
            grounding_insights=grounding_insights_data,
            optimization_results=optimization_results,
            research_coverage=research_coverage
        )
    
    
    
    async def enhance_section(self, section: BlogOutlineSection, focus: str = "general improvement") -> BlogOutlineSection:
        """
        Enhance a single section using AI with research context.
        
        Args:
            section: The section to enhance
            focus: Enhancement focus area (e.g., "SEO optimization", "engagement", "comprehensiveness")
            
        Returns:
            Enhanced section with improved content
        """
        logger.info(f"Enhancing section '{section.heading}' with focus: {focus}")
        enhanced_section = await self.section_enhancer.enhance(section, focus)
        logger.info(f"✅ Section enhancement completed for '{section.heading}'")
        return enhanced_section
    
    async def optimize_outline(self, outline: List[BlogOutlineSection], focus: str = "comprehensive optimization") -> List[BlogOutlineSection]:
        """
        Optimize an entire outline for better flow, SEO, and engagement.
        
        Args:
            outline: List of sections to optimize
            focus: Optimization focus area
            
        Returns:
            Optimized outline with improved flow and engagement
        """
        logger.info(f"Optimizing outline with {len(outline)} sections, focus: {focus}")
        optimized_outline = await self.outline_optimizer.optimize(outline, focus)
        logger.info(f"✅ Outline optimization completed for {len(optimized_outline)} sections")
        return optimized_outline
    
    def rebalance_outline_word_counts(self, outline: List[BlogOutlineSection], target_words: int) -> List[BlogOutlineSection]:
        """
        Rebalance word count distribution across outline sections.
        
        Args:
            outline: List of sections to rebalance
            target_words: Total target word count
            
        Returns:
            Outline with rebalanced word counts
        """
        logger.info(f"Rebalancing word counts for {len(outline)} sections, target: {target_words} words")
        rebalanced_outline = self.outline_optimizer.rebalance_word_counts(outline, target_words)
        logger.info(f"✅ Word count rebalancing completed")
        return rebalanced_outline
    
    def get_grounding_insights(self, research_data) -> Dict[str, Any]:
        """
        Get grounding metadata insights for research data.
        
        Args:
            research_data: Research data with grounding metadata
            
        Returns:
            Dictionary containing grounding insights and analysis
        """
        logger.info("Extracting grounding insights from research data...")
        insights = self.grounding_engine.extract_contextual_insights(research_data.grounding_metadata)
        logger.info(f"✅ Extracted {len(insights)} grounding insight categories")
        return insights
    
    def get_authority_sources(self, research_data) -> List[Tuple]:
        """
        Get high-authority sources from grounding metadata.
        
        Args:
            research_data: Research data with grounding metadata
            
        Returns:
            List of (chunk, authority_score) tuples sorted by authority
        """
        logger.info("Identifying high-authority sources from grounding metadata...")
        authority_sources = self.grounding_engine.get_authority_sources(research_data.grounding_metadata)
        logger.info(f"✅ Identified {len(authority_sources)} high-authority sources")
        return authority_sources
    
    def get_high_confidence_insights(self, research_data) -> List[str]:
        """
        Get high-confidence insights from grounding metadata.
        
        Args:
            research_data: Research data with grounding metadata
            
        Returns:
            List of high-confidence insights
        """
        logger.info("Extracting high-confidence insights from grounding metadata...")
        insights = self.grounding_engine.get_high_confidence_insights(research_data.grounding_metadata)
        logger.info(f"✅ Extracted {len(insights)} high-confidence insights")
        return insights
    
    
    
