"""
Predictive Intelligence Tools for Meta Ads MCP Server

This module provides forward-looking analysis tools that enable LLMs to make
proactive optimization decisions based on predictive modeling.
"""

from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
from dataclasses import dataclass
import statistics
from collections import defaultdict

from .meta_client import MetaClient
from .schemas import (
    PredictBudgetOutcomeRequest,
    PredictCreativeLifespanRequest,
    PredictOptimalTimingRequest,
    PredictAudienceExpansionRequest,
    PredictSeasonalityRequest,
    PredictCompetitivePressureRequest,
    PredictBudgetOutcomeResponse,
    PredictCreativeLifespanResponse,
    PredictOptimalTimingResponse,
    PredictAudienceExpansionResponse,
    PredictSeasonalityResponse,
    PredictCompetitivePressureResponse,
    BudgetPrediction,
    CreativeLifespanPrediction,
    TimingPrediction,
    AudienceExpansionPrediction,
    SeasonalityPrediction,
    CompetitivePressurePrediction,
)
from .logging import get_logger

logger = get_logger(__name__)


@dataclass
class PredictiveContext:
    """Context for predictive operations"""
    ad_account_id: str
    time_range: Dict[str, str]
    prediction_parameters: Dict[str, Any]
    historical_data: Dict[str, Any]


class PredictiveIntelligenceEngine:
    """Handles predictive intelligence operations for Meta Ads"""
    
    def __init__(self, client: MetaClient):
        self.client = client
    
    async def predict_budget_outcome(
        self, 
        request: PredictBudgetOutcomeRequest
    ) -> PredictBudgetOutcomeResponse:
        """Predict performance if budget changes are applied"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get historical performance data
            historical_data = await self._get_historical_performance(context, request.entity_type)
            
            # Get current performance
            current_performance = await self._get_current_performance(context, request.entity_id)
            
            # Predict budget outcome
            predictions = []
            for budget_scenario in request.budget_scenarios:
                prediction = await self._predict_budget_scenario(
                    current_performance, historical_data, budget_scenario, request.prediction_horizon
                )
                predictions.append(prediction)
            
            # Calculate confidence and recommendations
            confidence = await self._calculate_prediction_confidence(historical_data, request.prediction_horizon)
            recommendations = await self._generate_budget_recommendations(predictions, request.optimization_goals)
            
            return PredictBudgetOutcomeResponse(
                predictions=predictions,
                confidence=confidence,
                recommendations=recommendations,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                prediction_horizon=request.prediction_horizon,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting budget outcome: {e}")
            raise
    
    async def predict_creative_lifespan(
        self, 
        request: PredictCreativeLifespanRequest
    ) -> PredictCreativeLifespanResponse:
        """Predict when creative will be fatigued"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get creative performance history
            creative_history = await self._get_creative_performance_history(context, request.creative_ids)
            
            # Predict lifespan for each creative
            lifespan_predictions = []
            for creative_id in request.creative_ids:
                if creative_id in creative_history:
                    prediction = await self._predict_creative_fatigue(
                        creative_id, creative_history[creative_id], request.fatigue_thresholds
                    )
                    lifespan_predictions.append(prediction)
            
            # Calculate overall insights
            insights = await self._calculate_creative_insights(lifespan_predictions)
            recommendations = await self._generate_creative_recommendations(lifespan_predictions)
            
            return PredictCreativeLifespanResponse(
                lifespan_predictions=lifespan_predictions,
                insights=insights,
                recommendations=recommendations,
                fatigue_thresholds=request.fatigue_thresholds,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting creative lifespan: {e}")
            raise
    
    async def predict_optimal_timing(
        self, 
        request: PredictOptimalTimingRequest
    ) -> PredictOptimalTimingResponse:
        """Predict best hours/days for campaign"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get hourly performance data
            hourly_data = await self._get_hourly_performance_data(context, request.entity_id)
            
            # Get daily performance data
            daily_data = await self._get_daily_performance_data(context, request.entity_id)
            
            # Predict optimal timing
            timing_predictions = await self._predict_optimal_timing_patterns(
                hourly_data, daily_data, request.optimization_metrics
            )
            
            # Generate scheduling recommendations
            recommendations = await self._generate_timing_recommendations(
                timing_predictions, request.scheduling_constraints
            )
            
            return PredictOptimalTimingResponse(
                timing_predictions=timing_predictions,
                recommendations=recommendations,
                optimization_metrics=request.optimization_metrics,
                entity_id=request.entity_id,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting optimal timing: {e}")
            raise
    
    async def predict_audience_expansion_impact(
        self, 
        request: PredictAudienceExpansionRequest
    ) -> PredictAudienceExpansionResponse:
        """Model impact of audience expansion"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get current audience performance
            current_audience_data = await self._get_current_audience_performance(context, request.entity_id)
            
            # Get expansion scenarios
            expansion_scenarios = await self._get_audience_expansion_scenarios(
                current_audience_data, request.expansion_options
            )
            
            # Predict impact for each scenario
            expansion_predictions = []
            for scenario in expansion_scenarios:
                prediction = await self._predict_audience_expansion_impact(
                    current_audience_data, scenario, request.impact_metrics
                )
                expansion_predictions.append(prediction)
            
            # Calculate risk assessment
            risk_assessment = await self._assess_expansion_risks(expansion_predictions)
            recommendations = await self._generate_expansion_recommendations(expansion_predictions)
            
            return PredictAudienceExpansionResponse(
                expansion_predictions=expansion_predictions,
                risk_assessment=risk_assessment,
                recommendations=recommendations,
                expansion_options=request.expansion_options,
                entity_id=request.entity_id,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting audience expansion impact: {e}")
            raise
    
    async def predict_seasonality_adjustment(
        self, 
        request: PredictSeasonalityRequest
    ) -> PredictSeasonalityResponse:
        """Predict seasonal performance patterns"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get historical seasonal data
            seasonal_data = await self._get_seasonal_performance_data(context, request.entity_id)
            
            # Analyze seasonal patterns
            seasonal_patterns = await self._analyze_seasonal_patterns(
                seasonal_data, request.seasonal_periods
            )
            
            # Predict future seasonal performance
            seasonal_predictions = await self._predict_seasonal_performance(
                seasonal_patterns, request.prediction_periods
            )
            
            # Generate seasonal recommendations
            recommendations = await self._generate_seasonal_recommendations(
                seasonal_predictions, request.business_goals
            )
            
            return PredictSeasonalityResponse(
                seasonal_predictions=seasonal_predictions,
                seasonal_patterns=seasonal_patterns,
                recommendations=recommendations,
                seasonal_periods=request.seasonal_periods,
                entity_id=request.entity_id,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting seasonality: {e}")
            raise
    
    async def predict_competitive_pressure(
        self, 
        request: PredictCompetitivePressureRequest
    ) -> PredictCompetitivePressureResponse:
        """Estimate competitive pressure in auction"""
        try:
            context = PredictiveContext(
                ad_account_id=request.ad_account_id,
                time_range=request.time_range,
                prediction_parameters=request.prediction_parameters,
                historical_data={}
            )
            
            # Get auction insights data
            auction_data = await self._get_auction_insights_data(context, request.entity_id)
            
            # Analyze competitive trends
            competitive_trends = await self._analyze_competitive_trends(auction_data)
            
            # Predict competitive pressure
            pressure_predictions = await self._predict_competitive_pressure(
                competitive_trends, request.prediction_horizon
            )
            
            # Generate competitive recommendations
            recommendations = await self._generate_competitive_recommendations(
                pressure_predictions, request.competitive_strategy
            )
            
            return PredictCompetitivePressureResponse(
                pressure_predictions=pressure_predictions,
                competitive_trends=competitive_trends,
                recommendations=recommendations,
                prediction_horizon=request.prediction_horizon,
                entity_id=request.entity_id,
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error predicting competitive pressure: {e}")
            raise
    
    async def _get_historical_performance(
        self, 
        context: PredictiveContext, 
        entity_type: str
    ) -> List[Dict[str, Any]]:
        """Get historical performance data for prediction"""
        try:
            # Get insights with date breakdown for historical analysis
            path = f"{context.ad_account_id}/insights"
            params = {
                "level": entity_type,
                "fields": "spend,conversions,impressions,clicks,ctr,cpc,roas",
                "time_range": context.time_range,
                "breakdowns": ["date"],
                "limit": 1000
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response.get("data", [])
            
        except Exception as e:
            logger.error(f"Error getting historical performance: {e}")
            return []
    
    async def _get_current_performance(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> Dict[str, Any]:
        """Get current performance data"""
        try:
            # Get current insights
            path = f"{entity_id}/insights"
            params = {
                "fields": "spend,conversions,impressions,clicks,ctr,cpc,roas",
                "time_range": {"since": "7_days_ago", "until": "today"},
                "limit": 1
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            data = response.get("data", [])
            return data[0] if data else {}
            
        except Exception as e:
            logger.error(f"Error getting current performance: {e}")
            return {}
    
    async def _predict_budget_scenario(
        self, 
        current_performance: Dict[str, Any], 
        historical_data: List[Dict[str, Any]], 
        budget_scenario: Dict[str, Any],
        prediction_horizon: int
    ) -> BudgetPrediction:
        """Predict performance for a budget scenario"""
        try:
            current_budget = float(current_performance.get("daily_budget", 0))
            new_budget = budget_scenario.get("budget", current_budget)
            
            # Calculate budget change ratio
            budget_ratio = new_budget / current_budget if current_budget > 0 else 1.0
            
            # Predict performance based on historical scaling patterns
            predicted_spend = float(current_performance.get("spend", 0)) * budget_ratio
            predicted_conversions = float(current_performance.get("conversions", 0)) * (budget_ratio ** 0.8)  # Diminishing returns
            predicted_impressions = float(current_performance.get("impressions", 0)) * (budget_ratio ** 0.9)
            predicted_clicks = float(current_performance.get("clicks", 0)) * (budget_ratio ** 0.85)
            
            # Calculate predicted metrics
            predicted_ctr = (predicted_clicks / predicted_impressions * 100) if predicted_impressions > 0 else 0
            predicted_cpc = (predicted_spend / predicted_clicks) if predicted_clicks > 0 else 0
            predicted_roas = (predicted_conversions / predicted_spend) if predicted_spend > 0 else 0
            
            # Calculate confidence based on historical variance
            confidence = self._calculate_budget_prediction_confidence(historical_data, budget_ratio)
            
            return BudgetPrediction(
                scenario_name=budget_scenario.get("name", "Budget Change"),
                current_budget=current_budget,
                predicted_budget=new_budget,
                predicted_spend=predicted_spend,
                predicted_conversions=predicted_conversions,
                predicted_impressions=predicted_impressions,
                predicted_clicks=predicted_clicks,
                predicted_ctr=predicted_ctr,
                predicted_cpc=predicted_cpc,
                predicted_roas=predicted_roas,
                confidence=confidence,
                risk_level=self._assess_budget_risk(budget_ratio)
            )
            
        except Exception as e:
            logger.error(f"Error predicting budget scenario: {e}")
            return BudgetPrediction(
                scenario_name=budget_scenario.get("name", "Budget Change"),
                current_budget=0,
                predicted_budget=0,
                predicted_spend=0,
                predicted_conversions=0,
                predicted_impressions=0,
                predicted_clicks=0,
                predicted_ctr=0,
                predicted_cpc=0,
                predicted_roas=0,
                confidence="low",
                risk_level="high"
            )
    
    async def _get_creative_performance_history(
        self, 
        context: PredictiveContext, 
        creative_ids: List[str]
    ) -> Dict[str, List[Dict[str, Any]]]:
        """Get creative performance history"""
        try:
            creative_history = {}
            
            for creative_id in creative_ids:
                # Get insights for creative with date breakdown
                path = f"{context.ad_account_id}/insights"
                params = {
                    "level": "ad",
                    "fields": "spend,conversions,impressions,clicks,ctr,cpc,frequency",
                    "time_range": context.time_range,
                    "breakdowns": ["date", "creative_id"],
                    "filtering": [{"field": "creative_id", "operator": "IN", "value": [creative_id]}],
                    "limit": 1000
                }
                
                response = await self.client.graph_request(
                    method="GET",
                    path=path,
                    params=params
                )
                
                data = response.get("data", [])
                creative_history[creative_id] = data
            
            return creative_history
            
        except Exception as e:
            logger.error(f"Error getting creative performance history: {e}")
            return {}
    
    async def _predict_creative_fatigue(
        self, 
        creative_id: str, 
        performance_history: List[Dict[str, Any]], 
        fatigue_thresholds: Dict[str, float]
    ) -> CreativeLifespanPrediction:
        """Predict when creative will be fatigued"""
        try:
            if not performance_history:
                return CreativeLifespanPrediction(
                    creative_id=creative_id,
                    current_frequency=0,
                    predicted_fatigue_date=None,
                    fatigue_probability=0,
                    performance_trend="unknown",
                    recommendations=[]
                )
            
            # Calculate current metrics
            latest_data = performance_history[-1] if performance_history else {}
            current_frequency = float(latest_data.get("frequency", 0))
            current_ctr = float(latest_data.get("ctr", 0))
            
            # Analyze performance trend
            performance_trend = self._analyze_creative_trend(performance_history)
            
            # Predict fatigue based on frequency and CTR trends
            fatigue_probability = self._calculate_fatigue_probability(
                current_frequency, current_ctr, fatigue_thresholds
            )
            
            # Predict fatigue date
            predicted_fatigue_date = self._predict_fatigue_date(
                performance_history, fatigue_thresholds
            )
            
            # Generate recommendations
            recommendations = self._generate_creative_recommendations(
                current_frequency, current_ctr, fatigue_probability
            )
            
            return CreativeLifespanPrediction(
                creative_id=creative_id,
                current_frequency=current_frequency,
                predicted_fatigue_date=predicted_fatigue_date,
                fatigue_probability=fatigue_probability,
                performance_trend=performance_trend,
                recommendations=recommendations
            )
            
        except Exception as e:
            logger.error(f"Error predicting creative fatigue: {e}")
            return CreativeLifespanPrediction(
                creative_id=creative_id,
                current_frequency=0,
                predicted_fatigue_date=None,
                fatigue_probability=0,
                performance_trend="unknown",
                recommendations=[]
            )
    
    async def _get_hourly_performance_data(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> List[Dict[str, Any]]:
        """Get hourly performance data"""
        try:
            # Get insights with hourly breakdown
            path = f"{entity_id}/insights"
            params = {
                "fields": "spend,conversions,impressions,clicks,ctr,cpc",
                "time_range": context.time_range,
                "breakdowns": ["hourly_stats_aggregated_by_advertiser_time_zone"],
                "limit": 1000
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response.get("data", [])
            
        except Exception as e:
            logger.error(f"Error getting hourly performance data: {e}")
            return []
    
    async def _get_daily_performance_data(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> List[Dict[str, Any]]:
        """Get daily performance data"""
        try:
            # Get insights with daily breakdown
            path = f"{entity_id}/insights"
            params = {
                "fields": "spend,conversions,impressions,clicks,ctr,cpc",
                "time_range": context.time_range,
                "breakdowns": ["date"],
                "limit": 1000
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response.get("data", [])
            
        except Exception as e:
            logger.error(f"Error getting daily performance data: {e}")
            return []
    
    async def _predict_optimal_timing_patterns(
        self, 
        hourly_data: List[Dict[str, Any]], 
        daily_data: List[Dict[str, Any]], 
        optimization_metrics: List[str]
    ) -> TimingPrediction:
        """Predict optimal timing patterns"""
        try:
            # Analyze hourly patterns
            hourly_patterns = self._analyze_hourly_patterns(hourly_data, optimization_metrics)
            
            # Analyze daily patterns
            daily_patterns = self._analyze_daily_patterns(daily_data, optimization_metrics)
            
            # Find optimal hours
            optimal_hours = self._find_optimal_hours(hourly_patterns, optimization_metrics)
            
            # Find optimal days
            optimal_days = self._find_optimal_days(daily_patterns, optimization_metrics)
            
            # Calculate timing efficiency
            timing_efficiency = self._calculate_timing_efficiency(
                hourly_patterns, daily_patterns, optimization_metrics
            )
            
            return TimingPrediction(
                optimal_hours=optimal_hours,
                optimal_days=optimal_days,
                hourly_patterns=hourly_patterns,
                daily_patterns=daily_patterns,
                timing_efficiency=timing_efficiency,
                confidence="medium"  # Would calculate actual confidence
            )
            
        except Exception as e:
            logger.error(f"Error predicting optimal timing patterns: {e}")
            return TimingPrediction(
                optimal_hours=[],
                optimal_days=[],
                hourly_patterns={},
                daily_patterns={},
                timing_efficiency=0,
                confidence="low"
            )
    
    async def _get_current_audience_performance(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> Dict[str, Any]:
        """Get current audience performance data"""
        try:
            # Get insights with audience breakdown
            path = f"{entity_id}/insights"
            params = {
                "fields": "spend,conversions,impressions,clicks,ctr,cpc,reach,frequency",
                "time_range": {"since": "7_days_ago", "until": "today"},
                "limit": 1
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            data = response.get("data", [])
            return data[0] if data else {}
            
        except Exception as e:
            logger.error(f"Error getting current audience performance: {e}")
            return {}
    
    async def _get_audience_expansion_scenarios(
        self, 
        current_audience_data: Dict[str, Any], 
        expansion_options: List[str]
    ) -> List[Dict[str, Any]]:
        """Get audience expansion scenarios"""
        try:
            scenarios = []
            
            for option in expansion_options:
                if option == "age_expansion":
                    scenario = {
                        "name": "Age Range Expansion",
                        "description": "Expand age targeting by 5 years on each side",
                        "estimated_reach_increase": 1.3,
                        "estimated_cpc_increase": 1.1
                    }
                elif option == "geo_expansion":
                    scenario = {
                        "name": "Geographic Expansion",
                        "description": "Add adjacent geographic regions",
                        "estimated_reach_increase": 1.5,
                        "estimated_cpc_increase": 1.2
                    }
                elif option == "interest_expansion":
                    scenario = {
                        "name": "Interest Expansion",
                        "description": "Add related interest categories",
                        "estimated_reach_increase": 1.4,
                        "estimated_cpc_increase": 1.15
                    }
                else:
                    scenario = {
                        "name": f"Custom {option}",
                        "description": f"Custom expansion scenario: {option}",
                        "estimated_reach_increase": 1.2,
                        "estimated_cpc_increase": 1.05
                    }
                
                scenarios.append(scenario)
            
            return scenarios
            
        except Exception as e:
            logger.error(f"Error getting audience expansion scenarios: {e}")
            return []
    
    async def _predict_audience_expansion_impact(
        self, 
        current_audience_data: Dict[str, Any], 
        scenario: Dict[str, Any], 
        impact_metrics: List[str]
    ) -> AudienceExpansionPrediction:
        """Predict impact of audience expansion"""
        try:
            current_reach = float(current_audience_data.get("reach", 0))
            current_spend = float(current_audience_data.get("spend", 0))
            current_conversions = float(current_audience_data.get("conversions", 0))
            current_cpc = float(current_audience_data.get("cpc", 0))
            
            # Calculate predicted metrics
            reach_increase = scenario.get("estimated_reach_increase", 1.0)
            cpc_increase = scenario.get("estimated_cpc_increase", 1.0)
            
            predicted_reach = current_reach * reach_increase
            predicted_cpc = current_cpc * cpc_increase
            predicted_spend = current_spend * reach_increase * cpc_increase
            predicted_conversions = current_conversions * (reach_increase ** 0.8)  # Diminishing returns
            
            # Calculate efficiency metrics
            predicted_roas = (predicted_conversions / predicted_spend) if predicted_spend > 0 else 0
            predicted_ctr = (predicted_conversions / predicted_reach * 100) if predicted_reach > 0 else 0
            baseline_roas = (current_conversions / current_spend) if current_spend > 0 else 0
            
            return AudienceExpansionPrediction(
                scenario_name=scenario.get("name", "Unknown"),
                current_reach=current_reach,
                predicted_reach=predicted_reach,
                current_spend=current_spend,
                predicted_spend=predicted_spend,
                current_conversions=current_conversions,
                predicted_conversions=predicted_conversions,
                current_cpc=current_cpc,
                predicted_cpc=predicted_cpc,
                predicted_roas=predicted_roas,
                predicted_ctr=predicted_ctr,
                reach_increase_percentage=(reach_increase - 1) * 100,
                efficiency_impact="positive" if predicted_roas > baseline_roas else "negative"
            )
            
        except Exception as e:
            logger.error(f"Error predicting audience expansion impact: {e}")
            return AudienceExpansionPrediction(
                scenario_name=scenario.get("name", "Unknown"),
                current_reach=0,
                predicted_reach=0,
                current_spend=0,
                predicted_spend=0,
                current_conversions=0,
                predicted_conversions=0,
                current_cpc=0,
                predicted_cpc=0,
                predicted_roas=0,
                predicted_ctr=0,
                reach_increase_percentage=0,
                efficiency_impact="unknown"
            )
    
    async def _get_seasonal_performance_data(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> List[Dict[str, Any]]:
        """Get seasonal performance data"""
        try:
            # Get insights with date breakdown for seasonal analysis
            path = f"{entity_id}/insights"
            params = {
                "fields": "spend,conversions,impressions,clicks,ctr,cpc",
                "time_range": context.time_range,
                "breakdowns": ["date"],
                "limit": 1000
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response.get("data", [])
            
        except Exception as e:
            logger.error(f"Error getting seasonal performance data: {e}")
            return []
    
    async def _analyze_seasonal_patterns(
        self, 
        seasonal_data: List[Dict[str, Any]], 
        seasonal_periods: List[str]
    ) -> Dict[str, Any]:
        """Analyze seasonal patterns in performance"""
        try:
            patterns = {}
            
            for period in seasonal_periods:
                if period == "monthly":
                    patterns["monthly"] = self._analyze_monthly_patterns(seasonal_data)
                elif period == "weekly":
                    patterns["weekly"] = self._analyze_weekly_patterns(seasonal_data)
                elif period == "quarterly":
                    patterns["quarterly"] = self._analyze_quarterly_patterns(seasonal_data)
            
            return patterns
            
        except Exception as e:
            logger.error(f"Error analyzing seasonal patterns: {e}")
            return {}
    
    async def _predict_seasonal_performance(
        self, 
        seasonal_patterns: Dict[str, Any], 
        prediction_periods: List[str]
    ) -> List[SeasonalityPrediction]:
        """Predict seasonal performance"""
        try:
            predictions = []
            
            for period in prediction_periods:
                # Simplified seasonal prediction
                prediction = SeasonalityPrediction(
                    period=period,
                    predicted_performance_multiplier=1.0,  # Would calculate based on patterns
                    confidence="medium",
                    seasonal_factors={},
                    recommendations=[]
                )
                predictions.append(prediction)
            
            return predictions
            
        except Exception as e:
            logger.error(f"Error predicting seasonal performance: {e}")
            return []
    
    async def _get_auction_insights_data(
        self, 
        context: PredictiveContext, 
        entity_id: str
    ) -> Dict[str, Any]:
        """Get auction insights data"""
        try:
            # Get auction insights
            path = f"{entity_id}/insights"
            params = {
                "fields": "auction_competition,auction_bid,auction_win_rate",
                "time_range": context.time_range,
                "limit": 1
            }
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            data = response.get("data", [])
            return data[0] if data else {}
            
        except Exception as e:
            logger.error(f"Error getting auction insights data: {e}")
            return {}
    
    async def _analyze_competitive_trends(
        self, 
        auction_data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Analyze competitive trends"""
        try:
            # Simplified competitive analysis
            competition_level = float(auction_data.get("auction_competition", 0))
            win_rate = float(auction_data.get("auction_win_rate", 0))
            
            return {
                "current_competition_level": competition_level,
                "current_win_rate": win_rate,
                "competition_trend": "stable",  # Would calculate actual trend
                "market_saturation": "medium"  # Would calculate based on data
            }
            
        except Exception as e:
            logger.error(f"Error analyzing competitive trends: {e}")
            return {}
    
    async def _predict_competitive_pressure(
        self, 
        competitive_trends: Dict[str, Any], 
        prediction_horizon: int
    ) -> List[CompetitivePressurePrediction]:
        """Predict competitive pressure"""
        try:
            predictions = []
            
            # Generate predictions for different time periods
            for i in range(1, prediction_horizon + 1):
                prediction = CompetitivePressurePrediction(
                    time_period=f"{i}_days",
                    predicted_competition_level=competitive_trends.get("current_competition_level", 0),
                    predicted_win_rate=competitive_trends.get("current_win_rate", 0),
                    predicted_cpc_impact="stable",  # Would calculate based on trends
                    confidence="medium",
                    recommendations=[]
                )
                predictions.append(prediction)
            
            return predictions
            
        except Exception as e:
            logger.error(f"Error predicting competitive pressure: {e}")
            return []
    
    def _calculate_budget_prediction_confidence(
        self, 
        historical_data: List[Dict[str, Any]], 
        budget_ratio: float
    ) -> str:
        """Calculate confidence in budget prediction"""
        try:
            if not historical_data or len(historical_data) < 7:
                return "low"
            
            # Calculate variance in historical performance
            spends = [float(d.get("spend", 0)) for d in historical_data]
            if len(spends) > 1:
                variance = statistics.variance(spends)
                if variance < 100:  # Low variance
                    return "high"
                elif variance < 1000:  # Medium variance
                    return "medium"
                else:  # High variance
                    return "low"
            
            return "medium"
            
        except Exception:
            return "low"
    
    def _assess_budget_risk(self, budget_ratio: float) -> str:
        """Assess risk level of budget change"""
        if budget_ratio > 2.0 or budget_ratio < 0.5:
            return "high"
        elif budget_ratio > 1.5 or budget_ratio < 0.7:
            return "medium"
        else:
            return "low"
    
    def _analyze_creative_trend(self, performance_history: List[Dict[str, Any]]) -> str:
        """Analyze creative performance trend"""
        try:
            if len(performance_history) < 3:
                return "insufficient_data"
            
            # Analyze CTR trend
            ctrs = [float(d.get("ctr", 0)) for d in performance_history[-5:]]  # Last 5 data points
            if len(ctrs) >= 2:
                if ctrs[-1] > ctrs[0] * 1.1:
                    return "improving"
                elif ctrs[-1] < ctrs[0] * 0.9:
                    return "declining"
                else:
                    return "stable"
            
            return "stable"
            
        except Exception:
            return "unknown"
    
    def _calculate_fatigue_probability(
        self, 
        current_frequency: float, 
        current_ctr: float, 
        fatigue_thresholds: Dict[str, float]
    ) -> float:
        """Calculate probability of creative fatigue"""
        try:
            frequency_threshold = fatigue_thresholds.get("frequency", 3.0)
            ctr_threshold = fatigue_thresholds.get("ctr", 1.0)
            
            # Simple fatigue probability calculation
            frequency_factor = min(current_frequency / frequency_threshold, 1.0)
            ctr_factor = max(0, 1.0 - (current_ctr / ctr_threshold))
            
            fatigue_probability = (frequency_factor + ctr_factor) / 2
            return min(fatigue_probability, 1.0)
            
        except Exception:
            return 0.5
    
    def _predict_fatigue_date(
        self, 
        performance_history: List[Dict[str, Any]], 
        fatigue_thresholds: Dict[str, float]
    ) -> Optional[str]:
        """Predict when creative will be fatigued"""
        try:
            if not performance_history:
                return None
            
            # Simplified fatigue date prediction
            # In reality, this would use more sophisticated modeling
            current_frequency = float(performance_history[-1].get("frequency", 0))
            frequency_threshold = fatigue_thresholds.get("frequency", 3.0)
            
            if current_frequency >= frequency_threshold:
                # Already fatigued
                return datetime.now().strftime("%Y-%m-%d")
            else:
                # Predict based on current frequency growth rate
                days_to_fatigue = int((frequency_threshold - current_frequency) * 7)  # Simplified
                fatigue_date = datetime.now() + timedelta(days=days_to_fatigue)
                return fatigue_date.strftime("%Y-%m-%d")
            
        except Exception:
            return None
    
    def _generate_creative_recommendations(
        self, 
        current_frequency: float, 
        current_ctr: float, 
        fatigue_probability: float
    ) -> List[str]:
        """Generate creative recommendations"""
        recommendations = []
        
        if fatigue_probability > 0.7:
            recommendations.append("Consider refreshing creative immediately")
        elif fatigue_probability > 0.4:
            recommendations.append("Monitor creative closely and prepare backup")
        
        if current_frequency > 3.0:
            recommendations.append("High frequency detected - consider audience expansion")
        
        if current_ctr < 1.0:
            recommendations.append("Low CTR - consider creative optimization")
        
        return recommendations
    
    def _analyze_hourly_patterns(
        self, 
        hourly_data: List[Dict[str, Any]], 
        optimization_metrics: List[str]
    ) -> Dict[str, Any]:
        """Analyze hourly performance patterns"""
        try:
            patterns = {}
            
            # Group data by hour
            hourly_performance = defaultdict(list)
            for data in hourly_data:
                hour = data.get("hourly_stats_aggregated_by_advertiser_time_zone", "0")
                hourly_performance[hour].append(data)
            
            # Calculate average performance by hour
            for hour, data_list in hourly_performance.items():
                if data_list:
                    avg_spend = statistics.mean([float(d.get("spend", 0)) for d in data_list])
                    avg_ctr = statistics.mean([float(d.get("ctr", 0)) for d in data_list])
                    patterns[hour] = {
                        "avg_spend": avg_spend,
                        "avg_ctr": avg_ctr,
                        "data_points": len(data_list)
                    }
            
            return patterns
            
        except Exception as e:
            logger.error(f"Error analyzing hourly patterns: {e}")
            return {}
    
    def _analyze_daily_patterns(
        self, 
        daily_data: List[Dict[str, Any]], 
        optimization_metrics: List[str]
    ) -> Dict[str, Any]:
        """Analyze daily performance patterns"""
        try:
            patterns = {}
            
            # Group data by day of week
            daily_performance = defaultdict(list)
            for data in daily_data:
                date_str = data.get("date", "")
                if date_str:
                    # Extract day of week from date
                    try:
                        date_obj = datetime.strptime(date_str, "%Y-%m-%d")
                        day_of_week = date_obj.strftime("%A")
                        daily_performance[day_of_week].append(data)
                    except ValueError:
                        continue
            
            # Calculate average performance by day
            for day, data_list in daily_performance.items():
                if data_list:
                    avg_spend = statistics.mean([float(d.get("spend", 0)) for d in data_list])
                    avg_ctr = statistics.mean([float(d.get("ctr", 0)) for d in data_list])
                    patterns[day] = {
                        "avg_spend": avg_spend,
                        "avg_ctr": avg_ctr,
                        "data_points": len(data_list)
                    }
            
            return patterns
            
        except Exception as e:
            logger.error(f"Error analyzing daily patterns: {e}")
            return {}
    
    def _find_optimal_hours(
        self, 
        hourly_patterns: Dict[str, Any], 
        optimization_metrics: List[str]
    ) -> List[str]:
        """Find optimal hours based on patterns"""
        try:
            if not hourly_patterns:
                return []
            
            # Sort hours by performance (using CTR as primary metric)
            sorted_hours = sorted(
                hourly_patterns.items(),
                key=lambda x: x[1].get("avg_ctr", 0),
                reverse=True
            )
            
            # Return top 3 hours
            return [hour for hour, _ in sorted_hours[:3]]
            
        except Exception:
            return []
    
    def _find_optimal_days(
        self, 
        daily_patterns: Dict[str, Any], 
        optimization_metrics: List[str]
    ) -> List[str]:
        """Find optimal days based on patterns"""
        try:
            if not daily_patterns:
                return []
            
            # Sort days by performance (using CTR as primary metric)
            sorted_days = sorted(
                daily_patterns.items(),
                key=lambda x: x[1].get("avg_ctr", 0),
                reverse=True
            )
            
            # Return top 3 days
            return [day for day, _ in sorted_days[:3]]
            
        except Exception:
            return []
    
    def _calculate_timing_efficiency(
        self, 
        hourly_patterns: Dict[str, Any], 
        daily_patterns: Dict[str, Any], 
        optimization_metrics: List[str]
    ) -> float:
        """Calculate timing efficiency score"""
        try:
            # Simplified efficiency calculation
            if not hourly_patterns and not daily_patterns:
                return 0.0
            
            # Calculate variance in performance (lower variance = higher efficiency)
            all_ctrs = []
            for patterns in [hourly_patterns, daily_patterns]:
                for data in patterns.values():
                    if isinstance(data, dict) and "avg_ctr" in data:
                        all_ctrs.append(data["avg_ctr"])
            
            if len(all_ctrs) > 1:
                variance = statistics.variance(all_ctrs)
                # Convert variance to efficiency score (0-1)
                efficiency = max(0, 1 - (variance / 10))  # Normalize variance
                return min(efficiency, 1.0)
            
            return 0.5
            
        except Exception:
            return 0.0
    
    def _analyze_monthly_patterns(self, seasonal_data: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Analyze monthly seasonal patterns"""
        try:
            monthly_performance = defaultdict(list)
            
            for data in seasonal_data:
                date_str = data.get("date", "")
                if date_str:
                    try:
                        date_obj = datetime.strptime(date_str, "%Y-%m-%d")
                        month = date_obj.strftime("%B")
                        monthly_performance[month].append(data)
                    except ValueError:
                        continue
            
            patterns = {}
            for month, data_list in monthly_performance.items():
                if data_list:
                    avg_spend = statistics.mean([float(d.get("spend", 0)) for d in data_list])
                    avg_conversions = statistics.mean([float(d.get("conversions", 0)) for d in data_list])
                    patterns[month] = {
                        "avg_spend": avg_spend,
                        "avg_conversions": avg_conversions,
                        "data_points": len(data_list)
                    }
            
            return patterns
            
        except Exception:
            return {}
    
    def _analyze_weekly_patterns(self, seasonal_data: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Analyze weekly seasonal patterns"""
        try:
            # Simplified weekly analysis
            return {"pattern": "weekly_analysis_placeholder"}
            
        except Exception:
            return {}
    
    def _analyze_quarterly_patterns(self, seasonal_data: List[Dict[str, Any]]) -> Dict[str, Any]:
        """Analyze quarterly seasonal patterns"""
        try:
            # Simplified quarterly analysis
            return {"pattern": "quarterly_analysis_placeholder"}
            
        except Exception:
            return {}
    
    async def _calculate_prediction_confidence(
        self, 
        historical_data: List[Dict[str, Any]], 
        prediction_horizon: int
    ) -> str:
        """Calculate overall prediction confidence"""
        try:
            if not historical_data or len(historical_data) < 7:
                return "low"
            
            # Calculate data quality metrics
            data_points = len(historical_data)
            time_span = prediction_horizon
            
            if data_points >= 30 and time_span <= 7:
                return "high"
            elif data_points >= 14 and time_span <= 14:
                return "medium"
            else:
                return "low"
                
        except Exception:
            return "low"
    
    async def _generate_budget_recommendations(
        self, 
        predictions: List[BudgetPrediction], 
        optimization_goals: List[str]
    ) -> List[str]:
        """Generate budget recommendations"""
        try:
            recommendations = []
            
            if not predictions:
                return ["Insufficient data for budget recommendations"]
            
            # Find best performing scenario
            best_scenario = max(predictions, key=lambda x: x.predicted_roas)
            
            if best_scenario.predicted_roas > 3.0:
                recommendations.append(f"Consider implementing {best_scenario.scenario_name} for optimal ROAS")
            
            # Check for high-risk scenarios
            high_risk_scenarios = [p for p in predictions if p.risk_level == "high"]
            if high_risk_scenarios:
                recommendations.append("Avoid high-risk budget changes without careful monitoring")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate budget recommendations"]
    
    async def _calculate_creative_insights(
        self, 
        lifespan_predictions: List[CreativeLifespanPrediction]
    ) -> Dict[str, Any]:
        """Calculate creative insights"""
        try:
            if not lifespan_predictions:
                return {}
            
            high_fatigue_creatives = [p for p in lifespan_predictions if p.fatigue_probability > 0.7]
            avg_fatigue_probability = statistics.mean([p.fatigue_probability for p in lifespan_predictions])
            
            return {
                "total_creatives_analyzed": len(lifespan_predictions),
                "high_fatigue_creatives": len(high_fatigue_creatives),
                "average_fatigue_probability": avg_fatigue_probability,
                "creatives_needing_attention": len(high_fatigue_creatives)
            }
            
        except Exception:
            return {}
    
    async def _generate_creative_recommendations(
        self, 
        lifespan_predictions: List[CreativeLifespanPrediction]
    ) -> List[str]:
        """Generate creative recommendations"""
        try:
            recommendations = []
            
            high_fatigue_creatives = [p for p in lifespan_predictions if p.fatigue_probability > 0.7]
            
            if high_fatigue_creatives:
                recommendations.append(f"Refresh {len(high_fatigue_creatives)} high-fatigue creatives immediately")
            
            recommendations.append("Implement creative rotation schedule to prevent fatigue")
            recommendations.append("Monitor frequency and CTR trends for early fatigue detection")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate creative recommendations"]
    
    async def _generate_timing_recommendations(
        self, 
        timing_predictions: TimingPrediction, 
        scheduling_constraints: List[str]
    ) -> List[str]:
        """Generate timing recommendations"""
        try:
            recommendations = []
            
            if timing_predictions.optimal_hours:
                recommendations.append(f"Focus ad delivery during optimal hours: {', '.join(timing_predictions.optimal_hours)}")
            
            if timing_predictions.optimal_days:
                recommendations.append(f"Optimize for best performing days: {', '.join(timing_predictions.optimal_days)}")
            
            if timing_predictions.timing_efficiency < 0.5:
                recommendations.append("Consider implementing dayparting to improve timing efficiency")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate timing recommendations"]
    
    async def _assess_expansion_risks(
        self, 
        expansion_predictions: List[AudienceExpansionPrediction]
    ) -> Dict[str, Any]:
        """Assess risks of audience expansion"""
        try:
            if not expansion_predictions:
                return {}
            
            high_impact_scenarios = [p for p in expansion_predictions if p.efficiency_impact == "negative"]
            avg_reach_increase = statistics.mean([p.reach_increase_percentage for p in expansion_predictions])
            
            return {
                "total_scenarios_analyzed": len(expansion_predictions),
                "high_risk_scenarios": len(high_impact_scenarios),
                "average_reach_increase": avg_reach_increase,
                "overall_risk_level": "high" if len(high_impact_scenarios) > len(expansion_predictions) / 2 else "medium"
            }
            
        except Exception:
            return {}
    
    async def _generate_expansion_recommendations(
        self, 
        expansion_predictions: List[AudienceExpansionPrediction]
    ) -> List[str]:
        """Generate audience expansion recommendations"""
        try:
            recommendations = []
            
            if not expansion_predictions:
                return ["No expansion scenarios to analyze"]
            
            # Find best performing scenario
            best_scenario = max(expansion_predictions, key=lambda x: x.predicted_roas)
            
            if best_scenario.predicted_roas > 2.0:
                recommendations.append(f"Consider implementing {best_scenario.scenario_name} for optimal performance")
            
            recommendations.append("Test expansion scenarios with small budgets first")
            recommendations.append("Monitor performance closely during expansion phase")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate expansion recommendations"]
    
    async def _generate_seasonal_recommendations(
        self, 
        seasonal_predictions: List[SeasonalityPrediction], 
        business_goals: List[str]
    ) -> List[str]:
        """Generate seasonal recommendations"""
        try:
            recommendations = []
            
            recommendations.append("Adjust budgets based on seasonal performance patterns")
            recommendations.append("Prepare creative variations for high-volume periods")
            recommendations.append("Implement seasonal bidding strategies")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate seasonal recommendations"]
    
    async def _generate_competitive_recommendations(
        self, 
        pressure_predictions: List[CompetitivePressurePrediction], 
        competitive_strategy: str
    ) -> List[str]:
        """Generate competitive recommendations"""
        try:
            recommendations = []
            
            recommendations.append("Monitor competitive pressure trends closely")
            recommendations.append("Adjust bidding strategy based on competition levels")
            recommendations.append("Consider creative differentiation to stand out")
            
            return recommendations
            
        except Exception:
            return ["Unable to generate competitive recommendations"]


# Global predictive engine instance
_predictive_engine: Optional[PredictiveIntelligenceEngine] = None


def get_predictive_engine() -> PredictiveIntelligenceEngine:
    """Get the global PredictiveIntelligenceEngine instance"""
    global _predictive_engine
    if _predictive_engine is None:
        from .meta_client import get_client
        _predictive_engine = PredictiveIntelligenceEngine(get_client())
    return _predictive_engine
