"""Predictive Intelligence Engine - Phase 2

ML-powered forecasting and proactive optimization for Meta Ads.
Predicts future performance, creative fatigue, audience saturation, and optimal actions.

Business Impact: Proactive optimization, reduced waste, better planning
Annual ROI: $300K-500K/year
"""

from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta

from .meta_client import MetaClient
from .base.engine import BaseEngine, EngineConfig
from .logging import get_logger

logger = get_logger(__name__)


class PredictiveIntelligenceEngine(BaseEngine):
    """Engine for ML-powered predictive analytics."""
    
    def __init__(self, client: MetaClient, config: Optional[EngineConfig] = None):
        """Initialize predictive intelligence engine."""
        super().__init__(client, config or EngineConfig())
        self.logger = logger
    
    async def forecast_performance(self, request: Any) -> Dict[str, Any]:
        """7/14/30-day performance forecast with confidence intervals.
        
        Uses time-series analysis to predict future metrics based on historical trends.
        
        Args:
            request: ForecastPerformanceRequest
            
        Returns:
            Forecast with predictions, confidence intervals, and trends
        """
        try:
            account_id = request.ad_account_id
            entity_id = request.entity_id
            forecast_days = request.forecast_days
            metrics = request.metrics
            
            # Fetch historical data (last 30 days for trends)
            historical_data = await self._fetch_historical_metrics(
                account_id, entity_id, request.entity_type, days=30
            )
            
            # Generate forecasts for each metric
            forecasts = {}
            for metric in metrics:
                forecast = self._generate_metric_forecast(
                    historical_data, metric, forecast_days
                )
                forecasts[metric] = forecast
            
            # Calculate overall trend and confidence
            trend_analysis = self._analyze_trends(historical_data)
            confidence_score = self._calculate_forecast_confidence(historical_data)
            
            result = {
                "entity_id": entity_id,
                "entity_type": request.entity_type,
                "forecast_period": f"{forecast_days} days",
                "forecasts": forecasts,
                "trend_analysis": trend_analysis,
                "confidence_score": confidence_score,
                "recommendations": self._generate_forecast_recommendations(forecasts, trend_analysis),
                "generated_at": datetime.utcnow().isoformat()
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error forecasting performance: {e}")
            raise
    
    async def predict_creative_fatigue(self, request: Any) -> Dict[str, Any]:
        """Predict when creative will hit fatigue based on frequency/CTR decline.
        
        Analyzes CTR trends and frequency buildup to predict fatigue date.
        
        Args:
            request: PredictCreativeFatigueRequest
            
        Returns:
            Fatigue prediction with estimated date, current health, recommendations
        """
        try:
            account_id = request.ad_account_id
            ad_id = request.ad_id
            fatigue_threshold = request.fatigue_threshold
            
            # Fetch ad performance with frequency data
            ad_data = await self._fetch_ad_performance_with_frequency(account_id, ad_id)
            
            # Analyze CTR decline trend
            ctr_trend = self._analyze_ctr_trend(ad_data)
            
            # Calculate current fatigue score (0-100)
            fatigue_score = self._calculate_fatigue_score(ad_data, ctr_trend)
            
            # Predict days until fatigue
            days_until_fatigue = self._predict_days_to_fatigue(
                ctr_trend, fatigue_threshold, fatigue_score
            )
            
            # Determine health status
            if fatigue_score < 30:
                status = "healthy"
            elif fatigue_score < 60:
                status = "warning"
            else:
                status = "fatigued"
            
            result = {
                "ad_id": ad_id,
                "fatigue_score": round(fatigue_score, 1),
                "status": status,
                "days_until_fatigue": days_until_fatigue,
                "estimated_fatigue_date": (datetime.utcnow() + timedelta(days=days_until_fatigue)).isoformat() if days_until_fatigue else None,
                "current_metrics": {
                    "frequency": ad_data.get("frequency", 0),
                    "ctr": ad_data.get("ctr", 0),
                    "ctr_decline_pct": ctr_trend.get("decline_pct", 0)
                },
                "recommendations": self._generate_fatigue_recommendations(fatigue_score, status, days_until_fatigue)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting creative fatigue: {e}")
            raise
    
    async def predict_budget_exhaustion(self, request: Any) -> Dict[str, Any]:
        """Predict when budget will run out at current spend rate.
        
        Calculates burn rate and estimates exhaustion date with recommendations.
        
        Args:
            request: PredictBudgetExhaustionRequest
            
        Returns:
            Budget exhaustion prediction with date, burn rate, recommendations
        """
        try:
            account_id = request.ad_account_id
            campaign_id = request.campaign_id
            
            # Fetch campaign budget info
            campaign_data = await self._fetch_campaign_budget_status(account_id, campaign_id)
            
            total_budget = campaign_data.get("lifetime_budget") or campaign_data.get("daily_budget", 0) * 30
            spent_amount = campaign_data.get("amount_spent", 0)
            remaining_budget = total_budget - spent_amount
            
            # Calculate daily burn rate (last 7 days)
            daily_burn_rate = await self._calculate_daily_burn_rate(account_id, campaign_id, days=7)
            
            # Predict exhaustion
            if daily_burn_rate > 0:
                days_until_exhaustion = remaining_budget / daily_burn_rate
                exhaustion_date = datetime.utcnow() + timedelta(days=days_until_exhaustion)
            else:
                days_until_exhaustion = None
                exhaustion_date = None
            
            # Calculate budget health
            budget_utilization = (spent_amount / total_budget * 100) if total_budget > 0 else 0
            
            result = {
                "campaign_id": campaign_id,
                "budget_status": {
                    "total_budget": total_budget,
                    "spent": spent_amount,
                    "remaining": remaining_budget,
                    "utilization_pct": round(budget_utilization, 1)
                },
                "burn_rate": {
                    "daily_average": round(daily_burn_rate, 2),
                    "trend": "increasing" if daily_burn_rate > spent_amount / 30 else "stable"
                },
                "prediction": {
                    "days_until_exhaustion": round(days_until_exhaustion, 1) if days_until_exhaustion else None,
                    "estimated_exhaustion_date": exhaustion_date.isoformat() if exhaustion_date else None,
                    "will_exhaust_early": days_until_exhaustion < 10 if days_until_exhaustion else False
                },
                "recommendations": self._generate_budget_exhaustion_recommendations(
                    remaining_budget, days_until_exhaustion, budget_utilization
                ) if request.include_recommendations else []
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting budget exhaustion: {e}")
            raise
    
    async def predict_audience_saturation(self, request: Any) -> Dict[str, Any]:
        """Predict when audience will be saturated (frequency, reach ceiling).
        
        Analyzes reach curve and frequency to predict saturation point.
        
        Args:
            request: PredictAudienceSaturationRequest
            
        Returns:
            Saturation prediction with timeline, current status, expansion recommendations
        """
        try:
            account_id = request.ad_account_id
            adset_id = request.adset_id
            saturation_threshold = request.saturation_threshold
            
            # Fetch audience delivery data
            delivery_data = await self._fetch_audience_delivery_data(account_id, adset_id)
            
            audience_size = delivery_data.get("target_audience_size", 0)
            current_reach = delivery_data.get("reach", 0)
            current_frequency = delivery_data.get("frequency", 0)
            
            # Calculate saturation metrics
            reach_pct = (current_reach / audience_size * 100) if audience_size > 0 else 0
            saturation_score = self._calculate_saturation_score(reach_pct, current_frequency, saturation_threshold)
            
            # Predict days to saturation
            reach_velocity = await self._calculate_reach_velocity(account_id, adset_id)
            days_to_saturation = self._predict_days_to_saturation(
                audience_size, current_reach, reach_velocity, saturation_threshold
            )
            
            # Determine status
            if saturation_score < 40:
                status = "healthy"
            elif saturation_score < 70:
                status = "approaching_saturation"
            else:
                status = "saturated"
            
            result = {
                "adset_id": adset_id,
                "saturation_score": round(saturation_score, 1),
                "status": status,
                "current_metrics": {
                    "audience_size": audience_size,
                    "current_reach": current_reach,
                    "reach_percentage": round(reach_pct, 1),
                    "frequency": round(current_frequency, 2)
                },
                "prediction": {
                    "days_to_saturation": round(days_to_saturation, 1) if days_to_saturation else None,
                    "estimated_saturation_date": (datetime.utcnow() + timedelta(days=days_to_saturation)).isoformat() if days_to_saturation else None
                },
                "recommendations": self._generate_saturation_recommendations(
                    saturation_score, status, days_to_saturation, audience_size
                )
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting audience saturation: {e}")
            raise
    
    async def predict_seasonal_trends(self, request: Any) -> Dict[str, Any]:
        """Predict seasonal patterns and upcoming peak/low periods.
        
        Analyzes historical data to identify seasonal trends and predict future patterns.
        
        Args:
            request: PredictSeasonalTrendsRequest
            
        Returns:
            Seasonal analysis with trends, peak periods, forecast
        """
        try:
            account_id = request.ad_account_id
            lookback_years = request.lookback_years
            forecast_months = request.forecast_months
            
            # Fetch historical data for seasonality analysis
            historical_data = await self._fetch_seasonal_historical_data(
                account_id, years=lookback_years
            )
            
            # Analyze seasonal patterns
            seasonal_patterns = self._analyze_seasonal_patterns(historical_data)
            
            # Identify peak and low periods
            peak_periods = self._identify_peak_periods(seasonal_patterns)
            low_periods = self._identify_low_periods(seasonal_patterns)
            
            # Generate forecast for next N months
            forecast = self._generate_seasonal_forecast(seasonal_patterns, forecast_months)
            
            result = {
                "analysis_period": f"{lookback_years} years",
                "forecast_period": f"{forecast_months} months",
                "seasonal_patterns": seasonal_patterns,
                "peak_periods": peak_periods,
                "low_periods": low_periods,
                "upcoming_forecast": forecast,
                "recommendations": self._generate_seasonal_recommendations(peak_periods, low_periods, forecast)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting seasonal trends: {e}")
            raise
    
    async def predict_competitor_activity(self, request: Any) -> Dict[str, Any]:
        """Predict CPM spikes from competitor activity.
        
        Analyzes historical CPM patterns to predict competitive pressure periods.
        
        Args:
            request: PredictCompetitorActivityRequest
            
        Returns:
            Competitor activity prediction with CPM forecasts, spike alerts
        """
        try:
            account_id = request.ad_account_id
            time_range = request.time_range
            forecast_days = request.forecast_days
            
            # Fetch CPM historical data
            cpm_data = await self._fetch_cpm_historical_data(account_id, time_range)
            
            # Analyze CPM trends and volatility
            cpm_analysis = self._analyze_cpm_trends(cpm_data)
            
            # Predict CPM for next N days
            cpm_forecast = self._forecast_cpm(cpm_data, forecast_days)
            
            # Identify predicted spikes
            predicted_spikes = self._identify_predicted_cpm_spikes(cpm_forecast, cpm_analysis["avg_cpm"])
            
            result = {
                "forecast_period": f"{forecast_days} days",
                "current_cpm": cpm_analysis["current_cpm"],
                "average_cpm": cpm_analysis["avg_cpm"],
                "cpm_volatility": cpm_analysis["volatility"],
                "cpm_forecast": cpm_forecast,
                "predicted_spikes": predicted_spikes,
                "competitive_pressure_score": self._calculate_competitive_pressure_score(cpm_analysis, predicted_spikes),
                "recommendations": self._generate_competitor_activity_recommendations(predicted_spikes, cpm_analysis)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting competitor activity: {e}")
            raise
    
    async def predict_optimal_budget(self, request: Any) -> Dict[str, Any]:
        """Calculate optimal budget to maximize ROAS based on marginal returns.
        
        Uses marginal analysis to find the budget sweet spot.
        
        Args:
            request: PredictOptimalBudgetRequest
            
        Returns:
            Optimal budget recommendation with expected ROAS, ROI projections
        """
        try:
            account_id = request.ad_account_id
            campaign_id = request.campaign_id
            target_roas = request.target_roas
            max_budget = request.max_budget
            
            # Fetch historical budget vs performance data
            budget_performance = await self._fetch_budget_performance_data(account_id, campaign_id)
            
            # Calculate marginal ROAS at different budget levels
            marginal_analysis = self._calculate_marginal_roas(budget_performance)
            
            # Find optimal budget
            optimal_budget = self._find_optimal_budget(
                marginal_analysis, target_roas, max_budget
            )
            
            # Project performance at optimal budget
            projected_performance = self._project_performance_at_budget(
                budget_performance, optimal_budget
            )
            
            current_budget = budget_performance[-1]["budget"] if budget_performance else 0
            budget_change_pct = ((optimal_budget - current_budget) / current_budget * 100) if current_budget > 0 else 0
            
            result = {
                "campaign_id": campaign_id,
                "current_budget": current_budget,
                "optimal_budget": round(optimal_budget, 2),
                "budget_change": {
                    "amount": round(optimal_budget - current_budget, 2),
                    "percentage": round(budget_change_pct, 1)
                },
                "projected_performance": projected_performance,
                "marginal_analysis": marginal_analysis,
                "constraints": {
                    "target_roas": target_roas,
                    "max_budget": max_budget
                },
                "recommendations": self._generate_optimal_budget_recommendations(
                    optimal_budget, current_budget, projected_performance
                )
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting optimal budget: {e}")
            raise
    
    async def predict_scaling_impact(self, request: Any) -> Dict[str, Any]:
        """Predict impact of scaling budget by X% (will performance hold?).
        
        Models performance degradation when scaling spend.
        
        Args:
            request: PredictScalingImpactRequest
            
        Returns:
            Scaling impact prediction with performance projections, risk assessment
        """
        try:
            account_id = request.ad_account_id
            campaign_id = request.campaign_id
            scale_percentage = request.scale_percentage
            time_range = request.time_range
            
            # Fetch current performance
            current_performance = await self._fetch_current_performance(account_id, campaign_id, time_range)
            
            current_budget = current_performance.get("budget", 0)
            new_budget = current_budget * (1 + scale_percentage / 100)
            
            # Model scaling impact
            scaling_model = self._model_scaling_impact(current_performance, scale_percentage)
            
            # Predict performance at new budget
            predicted_performance = {
                "spend": new_budget,
                "conversions": scaling_model["predicted_conversions"],
                "roas": scaling_model["predicted_roas"],
                "cpa": scaling_model["predicted_cpa"],
                "efficiency_loss": scaling_model["efficiency_loss_pct"]
            }
            
            # Risk assessment
            risk_level = self._assess_scaling_risk(scale_percentage, scaling_model)
            
            result = {
                "campaign_id": campaign_id,
                "scale_percentage": scale_percentage,
                "current_performance": {
                    "budget": current_budget,
                    "conversions": current_performance.get("conversions", 0),
                    "roas": current_performance.get("roas", 0),
                    "cpa": current_performance.get("cpa", 0)
                },
                "predicted_performance": predicted_performance,
                "impact_analysis": {
                    "conversions_increase": predicted_performance["conversions"] - current_performance.get("conversions", 0),
                    "roas_change_pct": ((predicted_performance["roas"] / current_performance.get("roas", 1)) - 1) * 100,
                    "efficiency_loss_pct": scaling_model["efficiency_loss_pct"]
                },
                "risk_assessment": {
                    "risk_level": risk_level,
                    "confidence_score": scaling_model["confidence"]
                },
                "recommendations": self._generate_scaling_recommendations(risk_level, predicted_performance, scale_percentage)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting scaling impact: {e}")
            raise
    
    async def predict_audience_expansion_roi(self, request: Any) -> Dict[str, Any]:
        """Predict ROI of expanding to lookalike/interest audiences.
        
        Models performance of audience expansion strategies.
        
        Args:
            request: PredictAudienceExpansionROIRequest
            
        Returns:
            Expansion ROI prediction with expected performance, risk analysis
        """
        try:
            account_id = request.ad_account_id
            current_audience_id = request.current_audience_id
            expansion_type = request.expansion_type
            
            # Fetch current audience performance
            current_performance = await self._fetch_audience_performance(
                account_id, current_audience_id
            )
            
            # Model expansion performance
            expansion_model = self._model_audience_expansion(
                current_performance, expansion_type, request.expansion_parameters
            )
            
            # Calculate expected ROI
            expected_roi = self._calculate_expansion_roi(expansion_model)
            
            result = {
                "current_audience_id": current_audience_id,
                "expansion_type": expansion_type,
                "current_performance": current_performance,
                "predicted_performance": expansion_model["predicted_metrics"],
                "roi_analysis": expected_roi,
                "audience_size_increase": expansion_model["audience_size_increase"],
                "risk_factors": expansion_model["risk_factors"],
                "recommendations": self._generate_expansion_recommendations(expected_roi, expansion_model)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting audience expansion ROI: {e}")
            raise
    
    async def predict_test_winner(self, request: Any) -> Dict[str, Any]:
        """Predict A/B test winner before statistical significance.
        
        Uses Bayesian analysis to predict test outcome early.
        
        Args:
            request: PredictTestWinnerRequest
            
        Returns:
            Test winner prediction with probability, recommended action
        """
        try:
            account_id = request.ad_account_id
            test_id = request.test_id
            variant_ids = request.variant_ids
            confidence_level = request.confidence_level
            
            # Fetch current test performance
            test_data = await self._fetch_test_performance(account_id, variant_ids)
            
            # Bayesian analysis
            bayesian_analysis = self._bayesian_test_analysis(test_data, confidence_level)
            
            # Predict winner
            predicted_winner = bayesian_analysis["likely_winner"]
            win_probability = bayesian_analysis["win_probability"]
            
            # Calculate time to significance
            days_to_significance = self._estimate_days_to_significance(test_data, confidence_level)
            
            # Decision recommendation
            if win_probability >= confidence_level:
                recommendation = "stop_test_declare_winner"
            elif win_probability >= 0.80:
                recommendation = "lean_towards_winner_consider_stopping"
            else:
                recommendation = "continue_test"
            
            result = {
                "test_id": test_id,
                "variants": test_data,
                "predicted_winner": predicted_winner,
                "win_probability": round(win_probability, 3),
                "confidence_level": confidence_level,
                "statistical_significance_reached": win_probability >= confidence_level,
                "days_to_significance": round(days_to_significance, 1) if days_to_significance else None,
                "recommendation": recommendation,
                "bayesian_analysis": bayesian_analysis,
                "insights": self._generate_test_insights(bayesian_analysis, test_data)
            }
            
            return result
            
        except Exception as e:
            self.logger.exception(f"Error predicting test winner: {e}")
            raise
    
    # Helper methods (simplified implementations)
    
    async def _fetch_historical_metrics(self, account_id: str, entity_id: str, entity_type: str, days: int) -> List[Dict]:
        """Fetch historical metrics for forecasting."""
        # Implementation would call Meta API
        return []
    
    def _generate_metric_forecast(self, historical_data: List[Dict], metric: str, days: int) -> Dict:
        """Generate forecast for a specific metric."""
        # Simple linear regression for demo
        return {
            "predictions": [],
            "confidence_intervals": {"lower": [], "upper": []},
            "trend": "increasing"
        }
    
    def _analyze_trends(self, historical_data: List[Dict]) -> Dict:
        """Analyze historical trends."""
        return {
            "trend_direction": "increasing",
            "volatility": "low",
            "seasonality_detected": False
        }
    
    def _calculate_forecast_confidence(self, historical_data: List[Dict]) -> float:
        """Calculate confidence score for forecast."""
        if not historical_data:
            return 0.5
        # Simplified - would use statistical methods
        return 0.85
    
    def _generate_forecast_recommendations(self, forecasts: Dict, trend_analysis: Dict) -> List[str]:
        """Generate actionable recommendations from forecast."""
        recommendations = []
        if trend_analysis.get("trend_direction") == "increasing":
            recommendations.append("Performance trending positively - consider increasing budget")
        else:
            recommendations.append("Performance declining - investigate creative fatigue or audience saturation")
        return recommendations
    
    async def _fetch_ad_performance_with_frequency(self, account_id: str, ad_id: str) -> Dict:
        """Fetch ad performance including frequency data."""
        return {
            "frequency": 2.5,
            "ctr": 1.8,
            "impressions": 50000,
            "clicks": 900
        }
    
    def _analyze_ctr_trend(self, ad_data: Dict) -> Dict:
        """Analyze CTR decline trend."""
        return {
            "decline_pct": 15,
            "trend": "declining",
            "rate_of_decline": 2.5  # % per week
        }
    
    def _calculate_fatigue_score(self, ad_data: Dict, ctr_trend: Dict) -> float:
        """Calculate creative fatigue score (0-100)."""
        frequency = ad_data.get("frequency", 0)
        ctr_decline = ctr_trend.get("decline_pct", 0)
        
        # Simple scoring: frequency weight 60%, CTR decline 40%
        freq_score = min(frequency / 5.0 * 60, 60)  # Max at frequency 5
        decline_score = ctr_decline * 0.4
        
        return min(freq_score + decline_score, 100)
    
    def _predict_days_to_fatigue(self, ctr_trend: Dict, threshold: float, current_score: float) -> Optional[int]:
        """Predict days until creative hits fatigue threshold."""
        if current_score >= threshold * 100:
            return 0
        
        decline_rate = ctr_trend.get("rate_of_decline", 2.5)
        if decline_rate <= 0:
            return None
        
        points_to_fatigue = (threshold * 100) - current_score
        days = points_to_fatigue / (decline_rate / 7)  # Convert weekly to daily
        
        return max(int(days), 1)
    
    def _generate_fatigue_recommendations(self, score: float, status: str, days: Optional[int]) -> List[str]:
        """Generate creative fatigue recommendations."""
        recommendations = []
        
        if status == "fatigued":
            recommendations.append("⚠️ URGENT: Refresh creative immediately - performance degrading")
            recommendations.append("Launch new creative variations or pause this ad")
        elif status == "warning":
            recommendations.append(f"Prepare new creative - estimated {days} days until fatigue")
            recommendations.append("Consider A/B testing new variations now")
        else:
            recommendations.append("Creative healthy - monitor weekly")
        
        return recommendations
    
    async def _fetch_campaign_budget_status(self, account_id: str, campaign_id: str) -> Dict:
        """Fetch campaign budget and spend data."""
        return {
            "lifetime_budget": 10000,
            "daily_budget": None,
            "amount_spent": 6500
        }
    
    async def _calculate_daily_burn_rate(self, account_id: str, campaign_id: str, days: int) -> float:
        """Calculate average daily spend."""
        # Simplified - would fetch actual data
        return 280.5
    
    def _generate_budget_exhaustion_recommendations(
        self, remaining: float, days: Optional[float], utilization: float
    ) -> List[str]:
        """Generate budget exhaustion recommendations."""
        recommendations = []
        
        if days and days < 7:
            recommendations.append(f"⚠️ Budget will exhaust in {int(days)} days - increase budget or reduce spend")
        elif days and days < 14:
            recommendations.append(f"Budget running low - {int(days)} days remaining")
            recommendations.append("Plan budget extension to maintain performance")
        
        if utilization > 90:
            recommendations.append("90%+ budget utilized - immediate action required")
        
        return recommendations
    
    async def _fetch_audience_delivery_data(self, account_id: str, adset_id: str) -> Dict:
        """Fetch audience size, reach, and frequency."""
        return {
            "target_audience_size": 500000,
            "reach": 250000,
            "frequency": 2.8
        }
    
    def _calculate_saturation_score(self, reach_pct: float, frequency: float, threshold: float) -> float:
        """Calculate audience saturation score (0-100)."""
        # Reach component (60% weight)
        reach_score = min(reach_pct / 80 * 60, 60)  # 80% reach = max
        
        # Frequency component (40% weight)
        freq_score = min(frequency / threshold * 40, 40)
        
        return reach_score + freq_score
    
    async def _calculate_reach_velocity(self, account_id: str, adset_id: str) -> float:
        """Calculate daily reach increase rate."""
        # Simplified
        return 15000  # users per day
    
    def _predict_days_to_saturation(
        self, audience_size: int, current_reach: int, velocity: float, threshold: float
    ) -> Optional[int]:
        """Predict days until audience saturation."""
        if velocity <= 0:
            return None
        
        # Saturation at 70% reach or frequency > threshold
        saturation_reach = audience_size * 0.70
        remaining_reach = saturation_reach - current_reach
        
        if remaining_reach <= 0:
            return 0
        
        days = remaining_reach / velocity
        return max(int(days), 1)
    
    def _generate_saturation_recommendations(
        self, score: float, status: str, days: Optional[int], audience_size: int
    ) -> List[str]:
        """Generate audience saturation recommendations."""
        recommendations = []
        
        if status == "saturated":
            recommendations.append("⚠️ Audience saturated - expand targeting immediately")
            recommendations.append("Create lookalike audiences or broaden interests")
        elif status == "approaching_saturation":
            recommendations.append(f"Approaching saturation - {days} days until ceiling")
            recommendations.append("Prepare audience expansion strategy")
        else:
            recommendations.append("Audience healthy - monitor reach trends")
        
        return recommendations
    
    async def _fetch_seasonal_historical_data(self, account_id: str, years: int) -> List[Dict]:
        """Fetch multi-year historical data for seasonality."""
        return []
    
    def _analyze_seasonal_patterns(self, historical_data: List[Dict]) -> Dict:
        """Identify seasonal patterns in data."""
        return {
            "patterns_detected": True,
            "peak_months": ["November", "December"],
            "low_months": ["January", "February"]
        }
    
    def _identify_peak_periods(self, patterns: Dict) -> List[Dict]:
        """Identify peak performance periods."""
        return [
            {"period": "Q4", "performance_index": 1.45, "description": "Holiday season peak"}
        ]
    
    def _identify_low_periods(self, patterns: Dict) -> List[Dict]:
        """Identify low performance periods."""
        return [
            {"period": "Q1", "performance_index": 0.75, "description": "Post-holiday slowdown"}
        ]
    
    def _generate_seasonal_forecast(self, patterns: Dict, months: int) -> List[Dict]:
        """Generate seasonal forecast."""
        return []
    
    def _generate_seasonal_recommendations(
        self, peaks: List[Dict], lows: List[Dict], forecast: List[Dict]
    ) -> List[str]:
        """Generate seasonal planning recommendations."""
        return [
            "Increase budget 40-50% during Q4 peak season",
            "Plan creative refresh before holiday season",
            "Reduce spend 20-30% during Q1 low period"
        ]
    
    async def _fetch_cpm_historical_data(self, account_id: str, time_range: Dict) -> List[Dict]:
        """Fetch CPM historical data."""
        return []
    
    def _analyze_cpm_trends(self, cpm_data: List[Dict]) -> Dict:
        """Analyze CPM trends and volatility."""
        return {
            "current_cpm": 12.50,
            "avg_cpm": 10.80,
            "volatility": "moderate"
        }
    
    def _forecast_cpm(self, cpm_data: List[Dict], days: int) -> List[Dict]:
        """Forecast CPM for next N days."""
        return []
    
    def _identify_predicted_cpm_spikes(self, forecast: List[Dict], avg_cpm: float) -> List[Dict]:
        """Identify predicted CPM spikes."""
        return [
            {"date": "2024-12-15", "predicted_cpm": 18.50, "spike_pct": 71}
        ]
    
    def _calculate_competitive_pressure_score(self, analysis: Dict, spikes: List[Dict]) -> float:
        """Calculate competitive pressure score."""
        return 65.0
    
    def _generate_competitor_activity_recommendations(self, spikes: List[Dict], analysis: Dict) -> List[str]:
        """Generate competitor activity recommendations."""
        return [
            "CPM spike predicted Dec 15 - increase bids 20% to maintain delivery",
            "Consider shifting budget to lower-competition placements"
        ]
    
    async def _fetch_budget_performance_data(self, account_id: str, campaign_id: str) -> List[Dict]:
        """Fetch historical budget vs performance data."""
        return []
    
    def _calculate_marginal_roas(self, budget_performance: List[Dict]) -> Dict:
        """Calculate marginal ROAS at different budget levels."""
        return {
            "marginal_roas_curve": [],
            "diminishing_returns_point": 15000
        }
    
    def _find_optimal_budget(
        self, marginal_analysis: Dict, target_roas: Optional[float], max_budget: Optional[float]
    ) -> float:
        """Find optimal budget point."""
        # Simplified
        return 12500.0
    
    def _project_performance_at_budget(self, historical: List[Dict], budget: float) -> Dict:
        """Project performance at given budget."""
        return {
            "spend": budget,
            "conversions": 450,
            "revenue": 67500,
            "roas": 5.4
        }
    
    def _generate_optimal_budget_recommendations(
        self, optimal: float, current: float, projected: Dict
    ) -> List[str]:
        """Generate optimal budget recommendations."""
        change_pct = ((optimal - current) / current * 100) if current > 0 else 0
        
        if change_pct > 20:
            return [
                f"Increase budget by {abs(change_pct):.0f}% to ${optimal:.0f} for optimal ROAS",
                f"Expected ROAS: {projected['roas']:.1f}x"
            ]
        elif change_pct < -20:
            return [
                f"Reduce budget by {abs(change_pct):.0f}% to ${optimal:.0f} - diminishing returns detected",
                "Reallocate excess budget to higher-performing campaigns"
            ]
        else:
            return ["Current budget near optimal - maintain spend"]
    
    async def _fetch_current_performance(self, account_id: str, campaign_id: str, time_range: Dict) -> Dict:
        """Fetch current performance metrics."""
        return {
            "budget": 5000,
            "conversions": 180,
            "roas": 4.2,
            "cpa": 27.78
        }
    
    def _model_scaling_impact(self, current: Dict, scale_pct: float) -> Dict:
        """Model performance impact of scaling."""
        # Simplified diminishing returns model
        efficiency_loss = min(scale_pct * 0.15, 30)  # 15% loss per 100% scale, cap at 30%
        
        return {
            "predicted_conversions": current["conversions"] * (1 + scale_pct/100) * (1 - efficiency_loss/100),
            "predicted_roas": current["roas"] * (1 - efficiency_loss/100),
            "predicted_cpa": current["cpa"] * (1 + efficiency_loss/100),
            "efficiency_loss_pct": efficiency_loss,
            "confidence": 0.75
        }
    
    def _assess_scaling_risk(self, scale_pct: float, model: Dict) -> str:
        """Assess risk level of scaling."""
        if scale_pct > 100:
            return "high"
        elif scale_pct > 50:
            return "moderate"
        else:
            return "low"
    
    def _generate_scaling_recommendations(self, risk: str, predicted: Dict, scale_pct: float) -> List[str]:
        """Generate scaling recommendations."""
        if risk == "high":
            return [
                f"⚠️ {scale_pct}% scaling carries high risk - expect {predicted['efficiency_loss']:.0f}% efficiency loss",
                "Consider gradual scaling in 25-50% increments",
                "Expand audience targeting before aggressive scaling"
            ]
        elif risk == "moderate":
            return [
                f"Moderate risk - expect {predicted['efficiency_loss']:.0f}% efficiency loss",
                "Monitor first 3-5 days closely after scaling"
            ]
        else:
            return [
                f"Low risk scaling - proceed with {scale_pct}% increase",
                f"Expected ROAS: {predicted['roas']:.1f}x"
            ]
    
    async def _fetch_audience_performance(self, account_id: str, audience_id: str) -> Dict:
        """Fetch current audience performance."""
        return {
            "audience_size": 250000,
            "conversions": 120,
            "roas": 4.5,
            "cpa": 25.00
        }
    
    def _model_audience_expansion(self, current: Dict, expansion_type: str, params: Optional[Dict]) -> Dict:
        """Model audience expansion performance."""
        # Simplified model
        if expansion_type == "lookalike":
            predicted_roas = current["roas"] * 0.85  # 15% efficiency loss typical
            audience_multiplier = 3.0
        elif expansion_type == "interest":
            predicted_roas = current["roas"] * 0.75
            audience_multiplier = 5.0
        else:  # broad
            predicted_roas = current["roas"] * 0.60
            audience_multiplier = 10.0
        
        return {
            "predicted_metrics": {
                "roas": predicted_roas,
                "estimated_conversions": current["conversions"] * audience_multiplier * 0.70
            },
            "audience_size_increase": current["audience_size"] * audience_multiplier,
            "risk_factors": ["Conversion rate may decline with broader targeting"]
        }
    
    def _calculate_expansion_roi(self, model: Dict) -> Dict:
        """Calculate expansion ROI."""
        return {
            "expected_roas": model["predicted_metrics"]["roas"],
            "conversion_volume_increase": model["predicted_metrics"]["estimated_conversions"],
            "roi_score": 7.5  # out of 10
        }
    
    def _generate_expansion_recommendations(self, roi: Dict, model: Dict) -> List[str]:
        """Generate expansion recommendations."""
        if roi["roi_score"] > 7:
            return [
                "Strong expansion opportunity - proceed with testing",
                f"Expected ROAS: {roi['expected_roas']:.1f}x"
            ]
        else:
            return ["Expansion may dilute ROAS - test small before scaling"]
    
    async def _fetch_test_performance(self, account_id: str, variant_ids: List[str]) -> List[Dict]:
        """Fetch A/B test variant performance."""
        return []
    
    def _bayesian_test_analysis(self, test_data: List[Dict], confidence: float) -> Dict:
        """Bayesian analysis of test results."""
        return {
            "likely_winner": "variant_a",
            "win_probability": 0.89,
            "expected_lift": 15.2
        }
    
    def _estimate_days_to_significance(self, test_data: List[Dict], confidence: float) -> Optional[int]:
        """Estimate days until statistical significance."""
        return 5
    
    def _generate_test_insights(self, bayesian: Dict, test_data: List[Dict]) -> List[str]:
        """Generate test insights."""
        return [
            f"Variant A has {bayesian['win_probability']:.0%} probability of winning",
            f"Expected lift: {bayesian['expected_lift']:.1f}%"
        ]

