"""
Scenario Planning & Simulation for Meta Ads MCP Server

This module provides what-if analysis and simulation capabilities.
"""

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

from .meta_client import MetaClient
from .schemas import (
    SimulateBudgetIncreaseRequest,
    SimulateBidChangesRequest,
    SimulateAudienceExpansionRequest,
    SimulateCreativeRefreshRequest,
    SimulateSeasonalPlanningRequest,
    CompareStrategiesRequest,
    SimulateBudgetIncreaseResponse,
    SimulateBidChangesResponse,
    SimulateAudienceExpansionResponse,
    SimulateCreativeRefreshResponse,
    SimulateSeasonalPlanningResponse,
    CompareStrategiesResponse,
    ScenarioOutcome,
)
from .logging import get_logger

logger = get_logger(__name__)


class ScenarioPlanningEngine:
    """Handles scenario planning and simulation for Meta Ads"""
    
    def __init__(self, client: MetaClient):
        self.client = client
    
    async def simulate_budget_increase(
        self, 
        request: SimulateBudgetIncreaseRequest
    ) -> SimulateBudgetIncreaseResponse:
        """Simulate impact of budget increase"""
        try:
            logger.info(f"Simulating budget increase for {request.entity_id}")
            
            # Get current performance
            current_performance = await self._get_entity_performance(
                request.entity_id, request.time_range
            )
            
            # Project scenarios
            scenarios = []
            for increase_pct in request.budget_increase_percentages:
                outcome = await self._project_budget_scenario(
                    current_performance,
                    increase_pct,
                    request.assumptions
                )
                scenarios.append(outcome)
            
            # Identify best scenario
            best_scenario = max(scenarios, key=lambda s: s.projected_metrics.get("roas", 0))
            
            # Calculate risk assessment
            risk_assessment = self._assess_budget_increase_risk(
                current_performance, request.budget_increase_percentages, request.assumptions
            )
            
            return SimulateBudgetIncreaseResponse(
                current_performance=current_performance,
                scenarios=scenarios,
                recommended_scenario=best_scenario,
                risk_assessment=risk_assessment,
                assumptions_used=request.assumptions,
                confidence_level=self._calculate_scenario_confidence(current_performance),
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error simulating budget increase: {e}")
            raise
    
    async def simulate_bid_changes(
        self, 
        request: SimulateBidChangesRequest
    ) -> SimulateBidChangesResponse:
        """Model impact of bid changes"""
        try:
            logger.info(f"Simulating bid changes for {request.entity_id}")
            
            # Get current performance and bid data
            current_performance = await self._get_entity_performance(
                request.entity_id, request.time_range
            )
            
            current_bid = current_performance.get("avg_cpc", 1.0)
            
            # Project scenarios
            scenarios = []
            for new_bid in request.new_bid_amounts:
                outcome = await self._project_bid_scenario(
                    current_performance,
                    current_bid,
                    new_bid,
                    request.assumptions
                )
                scenarios.append(outcome)
            
            # Identify optimal bid
            if request.optimization_goal == "maximize_conversions":
                best_scenario = max(scenarios, key=lambda s: s.projected_metrics.get("conversions", 0))
            elif request.optimization_goal == "maximize_roas":
                best_scenario = max(scenarios, key=lambda s: s.projected_metrics.get("roas", 0))
            else:  # minimize_cpa
                best_scenario = min(scenarios, key=lambda s: s.projected_metrics.get("cpa", float('inf')))
            
            # Auction dynamics analysis
            auction_dynamics = self._analyze_auction_dynamics(
                current_bid, request.new_bid_amounts, current_performance
            )
            
            return SimulateBidChangesResponse(
                current_performance=current_performance,
                current_bid=current_bid,
                scenarios=scenarios,
                recommended_bid=best_scenario.scenario_name.split(": $")[1] if ": $" in best_scenario.scenario_name else str(best_scenario.projected_metrics.get("bid", current_bid)),
                auction_dynamics=auction_dynamics,
                optimization_goal=request.optimization_goal,
                confidence_level=self._calculate_scenario_confidence(current_performance),
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error simulating bid changes: {e}")
            raise
    
    async def simulate_audience_expansion(
        self, 
        request: SimulateAudienceExpansionRequest
    ) -> SimulateAudienceExpansionResponse:
        """Project impact of audience expansion"""
        try:
            logger.info(f"Simulating audience expansion for {request.entity_id}")
            
            # Get current audience performance
            current_performance = await self._get_entity_performance(
                request.entity_id, request.time_range
            )
            
            # Project expansion scenarios
            scenarios = []
            for expansion_strategy in request.expansion_strategies:
                outcome = await self._project_expansion_scenario(
                    current_performance,
                    expansion_strategy,
                    request.assumptions
                )
                scenarios.append(outcome)
            
            # Calculate reach projections
            reach_projections = self._calculate_reach_projections(
                current_performance, request.expansion_strategies
            )
            
            # Quality vs. volume tradeoff
            quality_volume_tradeoff = self._analyze_quality_volume_tradeoff(scenarios)
            
            # Recommended approach
            recommended = self._recommend_expansion_approach(
                scenarios, request.risk_tolerance
            )
            
            return SimulateAudienceExpansionResponse(
                current_performance=current_performance,
                scenarios=scenarios,
                reach_projections=reach_projections,
                quality_vs_volume_tradeoff=quality_volume_tradeoff,
                recommended_approach=recommended,
                risk_tolerance=request.risk_tolerance,
                confidence_level=self._calculate_scenario_confidence(current_performance),
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error simulating audience expansion: {e}")
            raise
    
    async def simulate_creative_refresh(
        self, 
        request: SimulateCreativeRefreshRequest
    ) -> SimulateCreativeRefreshResponse:
        """Forecast creative refresh impact"""
        try:
            logger.info(f"Simulating creative refresh for {request.entity_id}")
            
            # Get creative performance history
            creative_performance = await self._get_creative_performance_history(
                request.entity_id, request.time_range
            )
            
            # Analyze creative fatigue
            fatigue_analysis = self._analyze_creative_fatigue(creative_performance)
            
            # Project refresh scenarios
            scenarios = []
            for refresh_strategy in request.refresh_strategies:
                outcome = await self._project_refresh_scenario(
                    creative_performance,
                    refresh_strategy,
                    fatigue_analysis,
                    request.assumptions
                )
                scenarios.append(outcome)
            
            # Calculate expected lift
            expected_lift = self._calculate_expected_lift(
                fatigue_analysis, scenarios
            )
            
            # Timing recommendations
            timing_recommendations = self._recommend_refresh_timing(
                fatigue_analysis, request.refresh_strategies
            )
            
            return SimulateCreativeRefreshResponse(
                current_performance=creative_performance,
                fatigue_analysis=fatigue_analysis,
                scenarios=scenarios,
                expected_lift=expected_lift,
                timing_recommendations=timing_recommendations,
                confidence_level=self._calculate_scenario_confidence(creative_performance),
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error simulating creative refresh: {e}")
            raise
    
    async def simulate_seasonal_planning(
        self, 
        request: SimulateSeasonalPlanningRequest
    ) -> SimulateSeasonalPlanningResponse:
        """Plan for traffic increases"""
        try:
            logger.info(f"Simulating seasonal planning for {request.ad_account_id}")
            
            # Get historical seasonal data
            historical_data = await self._get_historical_seasonal_data(
                request.ad_account_id, request.seasonal_period
            )
            
            # Project scenarios with different preparation levels
            scenarios = []
            preparation_levels = ["minimal", "moderate", "aggressive"]
            
            for prep_level in preparation_levels:
                outcome = await self._project_seasonal_scenario(
                    historical_data,
                    prep_level,
                    request.expected_traffic_increase,
                    request.assumptions
                )
                scenarios.append(outcome)
            
            # Calculate capacity requirements
            capacity_requirements = self._calculate_capacity_requirements(
                historical_data, request.expected_traffic_increase
            )
            
            # Budget scaling plan
            budget_scaling_plan = self._create_budget_scaling_plan(
                historical_data, request.expected_traffic_increase, scenarios
            )
            
            # Risk mitigation strategies
            risk_mitigation = self._identify_seasonal_risks(
                historical_data, request.expected_traffic_increase
            )
            
            return SimulateSeasonalPlanningResponse(
                historical_performance=historical_data,
                scenarios=scenarios,
                capacity_requirements=capacity_requirements,
                budget_scaling_plan=budget_scaling_plan,
                risk_mitigation_strategies=risk_mitigation,
                preparation_timeline=self._create_preparation_timeline(request.seasonal_period),
                confidence_level=self._calculate_scenario_confidence(historical_data),
                seasonal_period=request.seasonal_period,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error simulating seasonal planning: {e}")
            raise
    
    async def compare_strategies(
        self, 
        request: CompareStrategiesRequest
    ) -> CompareStrategiesResponse:
        """A/B comparison before implementing"""
        try:
            logger.info(f"Comparing strategies for {request.entity_id}")
            
            # Get current baseline
            baseline_performance = await self._get_entity_performance(
                request.entity_id, request.time_range
            )
            
            # Project each strategy
            strategy_projections = []
            for strategy in request.strategies:
                projection = await self._project_strategy(
                    baseline_performance,
                    strategy,
                    request.evaluation_criteria
                )
                strategy_projections.append(projection)
            
            # Side-by-side comparison
            comparison_matrix = self._create_comparison_matrix(
                strategy_projections, request.evaluation_criteria
            )
            
            # Rank strategies
            ranked_strategies = self._rank_strategies(
                strategy_projections, request.evaluation_criteria
            )
            
            # Recommendation with rationale
            recommendation = self._recommend_strategy(
                ranked_strategies, request.risk_tolerance
            )
            
            # Implementation considerations
            implementation_considerations = self._assess_implementation_difficulty(
                request.strategies
            )
            
            return CompareStrategiesResponse(
                baseline_performance=baseline_performance,
                strategy_projections=strategy_projections,
                comparison_matrix=comparison_matrix,
                ranked_strategies=ranked_strategies,
                recommendation=recommendation,
                implementation_considerations=implementation_considerations,
                confidence_level=self._calculate_scenario_confidence(baseline_performance),
                time_range=request.time_range,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error comparing strategies: {e}")
            raise
    
    # Helper methods
    
    async def _get_entity_performance(
        self, 
        entity_id: str, 
        time_range: Dict[str, str]
    ) -> Dict[str, Any]:
        """Get current entity performance"""
        try:
            insights_response = await self.client.graph_request(
                method="GET",
                path=f"{entity_id}/insights",
                params={
                    "fields": "spend,conversions,roas,cpa,cpc,ctr,reach,frequency,impressions",
                    "time_range": time_range
                }
            )
            
            data = insights_response.get("data", [])
            if data:
                entry = data[0]
                return {
                    "spend": float(entry.get("spend", 0)),
                    "conversions": float(entry.get("conversions", 0)),
                    "roas": float(entry.get("roas", 0)),
                    "cpa": float(entry.get("cpa", 0)),
                    "avg_cpc": float(entry.get("cpc", 0)),
                    "ctr": float(entry.get("ctr", 0)),
                    "reach": int(entry.get("reach", 0)),
                    "frequency": float(entry.get("frequency", 0)),
                    "impressions": int(entry.get("impressions", 0))
                }
            
            # Return mock data if API fails
            return {
                "spend": 5000,
                "conversions": 250,
                "roas": 3.2,
                "cpa": 20,
                "avg_cpc": 1.5,
                "ctr": 0.02,
                "reach": 50000,
                "frequency": 2.5,
                "impressions": 125000
            }
            
        except Exception as e:
            logger.error(f"Error getting entity performance: {e}")
            # Return mock data
            return {
                "spend": 5000,
                "conversions": 250,
                "roas": 3.2,
                "cpa": 20,
                "avg_cpc": 1.5,
                "ctr": 0.02,
                "reach": 50000,
                "frequency": 2.5,
                "impressions": 125000
            }
    
    async def _project_budget_scenario(
        self, 
        current_performance: Dict[str, Any], 
        increase_pct: float,
        assumptions: Dict[str, Any]
    ) -> ScenarioOutcome:
        """Project budget increase scenario"""
        # Apply diminishing returns model
        efficiency_decay = assumptions.get("efficiency_decay_rate", 0.1)
        
        # Calculate new budget
        current_spend = current_performance["spend"]
        new_spend = current_spend * (1 + increase_pct / 100)
        
        # Project metrics with diminishing returns
        scaling_factor = (1 + increase_pct / 100) * (1 - efficiency_decay * increase_pct / 100)
        
        projected_conversions = current_performance["conversions"] * scaling_factor
        projected_cpa = new_spend / projected_conversions if projected_conversions > 0 else 0
        projected_roas = (projected_conversions * 50) / new_spend if new_spend > 0 else 0  # Assume $50 per conversion
        
        return ScenarioOutcome(
            scenario_name=f"Budget +{increase_pct}%",
            projected_metrics={
                "spend": new_spend,
                "conversions": projected_conversions,
                "cpa": projected_cpa,
                "roas": projected_roas,
                "efficiency_vs_current": (projected_roas / current_performance["roas"] - 1) * 100 if current_performance["roas"] > 0 else 0
            },
            expected_outcomes=[
                f"Spend increases to ${new_spend:.2f}",
                f"Conversions increase to {projected_conversions:.0f}",
                f"CPA changes to ${projected_cpa:.2f}",
                f"ROAS adjusts to {projected_roas:.2f}"
            ],
            risks=[
                "Diminishing returns may reduce efficiency" if increase_pct > 50 else "Moderate efficiency impact expected",
                "May require creative refresh to maintain performance" if increase_pct > 100 else "Current creative should suffice"
            ],
            probability=0.7 if increase_pct < 50 else 0.5 if increase_pct < 100 else 0.3
        )
    
    async def _project_bid_scenario(
        self, 
        current_performance: Dict[str, Any], 
        current_bid: float,
        new_bid: float,
        assumptions: Dict[str, Any]
    ) -> ScenarioOutcome:
        """Project bid change scenario"""
        bid_change_pct = ((new_bid - current_bid) / current_bid * 100) if current_bid > 0 else 0
        
        # Estimate volume and cost impact
        # Higher bids = more volume but higher cost
        volume_increase = bid_change_pct * 0.5  # 50% of bid increase translates to volume
        cost_increase = bid_change_pct * 0.8  # 80% of bid increase translates to cost
        
        projected_conversions = current_performance["conversions"] * (1 + volume_increase / 100)
        projected_spend = current_performance["spend"] * (1 + cost_increase / 100)
        projected_cpa = projected_spend / projected_conversions if projected_conversions > 0 else 0
        projected_roas = (projected_conversions * 50) / projected_spend if projected_spend > 0 else 0
        
        return ScenarioOutcome(
            scenario_name=f"Bid: ${new_bid:.2f}",
            projected_metrics={
                "bid": new_bid,
                "conversions": projected_conversions,
                "spend": projected_spend,
                "cpa": projected_cpa,
                "roas": projected_roas,
                "volume_change": volume_increase
            },
            expected_outcomes=[
                f"Volume changes by {volume_increase:+.1f}%",
                f"Cost changes by {cost_increase:+.1f}%",
                f"CPA adjusts to ${projected_cpa:.2f}",
                f"ROAS becomes {projected_roas:.2f}"
            ],
            risks=[
                "May not win enough auctions" if new_bid < current_bid else "May overpay in auctions",
                "Competitor bids may change" if abs(bid_change_pct) > 20 else "Minimal competitive impact"
            ],
            probability=0.6
        )
    
    async def _project_expansion_scenario(
        self, 
        current_performance: Dict[str, Any], 
        expansion_strategy: Dict[str, Any],
        assumptions: Dict[str, Any]
    ) -> ScenarioOutcome:
        """Project audience expansion scenario"""
        strategy_type = expansion_strategy.get("type", "lookalike")
        assumptions.get("quality_retention_rate", 0.8)
        
        # Estimate reach increase and quality impact
        if strategy_type == "lookalike_1":
            reach_increase = 100  # 100% increase
            quality_factor = 0.9  # 90% of original quality
        elif strategy_type == "lookalike_2_5":
            reach_increase = 300  # 300% increase
            quality_factor = 0.7  # 70% of original quality
        elif strategy_type == "interest_expansion":
            reach_increase = 150  # 150% increase
            quality_factor = 0.75  # 75% of original quality
        else:  # broad
            reach_increase = 500  # 500% increase
            quality_factor = 0.5  # 50% of original quality
        
        projected_reach = current_performance["reach"] * (1 + reach_increase / 100)
        projected_conversions = current_performance["conversions"] * (1 + reach_increase / 100) * quality_factor
        projected_spend = current_performance["spend"] * (1 + reach_increase / 100)
        projected_cpa = projected_spend / projected_conversions if projected_conversions > 0 else 0
        projected_roas = (projected_conversions * 50) / projected_spend if projected_spend > 0 else 0
        
        return ScenarioOutcome(
            scenario_name=f"Expansion: {strategy_type}",
            projected_metrics={
                "reach": projected_reach,
                "conversions": projected_conversions,
                "spend": projected_spend,
                "cpa": projected_cpa,
                "roas": projected_roas,
                "quality_score": quality_factor * 100
            },
            expected_outcomes=[
                f"Reach increases by {reach_increase}%",
                f"Conversions increase by {(projected_conversions / current_performance['conversions'] - 1) * 100:.1f}%",
                f"Quality retention: {quality_factor * 100:.0f}%",
                f"ROAS adjusts to {projected_roas:.2f}"
            ],
            risks=[
                "Audience quality may decline" if quality_factor < 0.7 else "Quality should remain stable",
                "May require budget increase" if reach_increase > 200 else "Current budget adequate"
            ],
            probability=0.65
        )
    
    async def _project_refresh_scenario(
        self, 
        creative_performance: Dict[str, Any], 
        refresh_strategy: Dict[str, Any],
        fatigue_analysis: Dict[str, Any],
        assumptions: Dict[str, Any]
    ) -> ScenarioOutcome:
        """Project creative refresh scenario"""
        current_fatigue = fatigue_analysis.get("fatigue_level", 0)
        refresh_type = refresh_strategy.get("type", "minor_update")
        
        # Estimate performance lift
        if refresh_type == "complete_overhaul":
            expected_lift = 30 + (current_fatigue * 0.5)  # Higher lift if more fatigued
            implementation_time = "2-3 weeks"
        elif refresh_type == "new_variations":
            expected_lift = 20 + (current_fatigue * 0.3)
            implementation_time = "1-2 weeks"
        else:  # minor_update
            expected_lift = 10 + (current_fatigue * 0.2)
            implementation_time = "< 1 week"
        
        projected_ctr = creative_performance.get("ctr", 0.02) * (1 + expected_lift / 100)
        projected_conversions = creative_performance.get("conversions", 250) * (1 + expected_lift / 100)
        projected_roas = creative_performance.get("roas", 3.2) * (1 + expected_lift * 0.5 / 100)
        
        return ScenarioOutcome(
            scenario_name=f"Refresh: {refresh_type}",
            projected_metrics={
                "ctr": projected_ctr,
                "conversions": projected_conversions,
                "roas": projected_roas,
                "expected_lift": expected_lift,
                "implementation_time": implementation_time
            },
            expected_outcomes=[
                f"CTR improves by {expected_lift:.1f}%",
                f"Conversions increase by {expected_lift:.1f}%",
                f"ROAS improves by {expected_lift * 0.5:.1f}%",
                f"Implementation: {implementation_time}"
            ],
            risks=[
                "New creative may underperform" if refresh_type == "complete_overhaul" else "Low risk with iterative approach",
                "Requires design resources" if refresh_type in ["complete_overhaul", "new_variations"] else "Minimal resources needed"
            ],
            probability=0.7 if refresh_type != "complete_overhaul" else 0.5
        )
    
    async def _project_seasonal_scenario(
        self, 
        historical_data: Dict[str, Any], 
        prep_level: str,
        expected_traffic_increase: float,
        assumptions: Dict[str, Any]
    ) -> ScenarioOutcome:
        """Project seasonal scenario"""
        # Calculate capture rate based on preparation
        if prep_level == "aggressive":
            capture_rate = 0.9
            budget_multiplier = 2.5
        elif prep_level == "moderate":
            capture_rate = 0.75
            budget_multiplier = 2.0
        else:  # minimal
            capture_rate = 0.5
            budget_multiplier = 1.5
        
        base_conversions = historical_data.get("avg_conversions", 250)
        projected_conversions = base_conversions * (1 + expected_traffic_increase / 100) * capture_rate
        
        base_spend = historical_data.get("avg_spend", 5000)
        projected_spend = base_spend * budget_multiplier
        
        projected_roas = (projected_conversions * 50) / projected_spend if projected_spend > 0 else 0
        
        return ScenarioOutcome(
            scenario_name=f"Seasonal: {prep_level} preparation",
            projected_metrics={
                "conversions": projected_conversions,
                "spend": projected_spend,
                "roas": projected_roas,
                "capture_rate": capture_rate * 100,
                "budget_multiplier": budget_multiplier
            },
            expected_outcomes=[
                f"Capture {capture_rate * 100:.0f}% of traffic increase",
                f"Achieve {projected_conversions:.0f} conversions",
                f"Budget: {budget_multiplier}x baseline",
                f"ROAS: {projected_roas:.2f}"
            ],
            risks=[
                "Competition increases during peak" if prep_level == "minimal" else "Well-positioned for competition",
                "Budget may be insufficient" if prep_level == "minimal" else "Budget adequate for traffic"
            ],
            probability=0.8 if prep_level != "minimal" else 0.6
        )
    
    async def _project_strategy(
        self, 
        baseline_performance: Dict[str, Any], 
        strategy: Dict[str, Any],
        evaluation_criteria: List[str]
    ) -> ScenarioOutcome:
        """Project a strategy"""
        strategy_name = strategy.get("name", "Strategy")
        changes = strategy.get("changes", {})
        
        # Simulate impact of changes
        impact_score = 1.0
        
        if "budget_change" in changes:
            impact_score *= (1 + changes["budget_change"] / 100 * 0.7)  # 70% efficiency
        
        if "bid_change" in changes:
            impact_score *= (1 + changes["bid_change"] / 100 * 0.5)  # 50% efficiency
        
        if "audience_expansion" in changes:
            impact_score *= 1.3  # 30% lift from expansion
        
        if "creative_refresh" in changes:
            impact_score *= 1.2  # 20% lift from refresh
        
        projected_conversions = baseline_performance["conversions"] * impact_score
        projected_spend = baseline_performance["spend"] * (1.1 if impact_score > 1.2 else 1.05)  # Spend increases slightly
        projected_roas = (projected_conversions * 50) / projected_spend if projected_spend > 0 else 0
        
        return ScenarioOutcome(
            scenario_name=strategy_name,
            projected_metrics={
                "conversions": projected_conversions,
                "spend": projected_spend,
                "roas": projected_roas,
                "impact_score": impact_score
            },
            expected_outcomes=[
                f"Conversions: {projected_conversions:.0f}",
                f"Spend: ${projected_spend:.2f}",
                f"ROAS: {projected_roas:.2f}",
                f"Overall impact: {(impact_score - 1) * 100:+.1f}%"
            ],
            risks=["Implementation complexity" if len(changes) > 2 else "Straightforward implementation"],
            probability=0.7
        )
    
    def _assess_budget_increase_risk(
        self, 
        current_performance: Dict[str, Any], 
        increases: List[float],
        assumptions: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Assess risks of budget increase"""
        max_increase = max(increases)
        
        if max_increase > 100:
            risk_level = "high"
            key_risks = [
                "Significant diminishing returns likely",
                "May require creative refresh",
                "Audience saturation possible"
            ]
        elif max_increase > 50:
            risk_level = "medium"
            key_risks = [
                "Moderate efficiency decline expected",
                "Monitor frequency closely"
            ]
        else:
            risk_level = "low"
            key_risks = [
                "Minimal efficiency impact",
                "Should scale well"
            ]
        
        return {
            "risk_level": risk_level,
            "key_risks": key_risks,
            "mitigation_strategies": [
                "Monitor performance daily",
                "Set automated rules for safety",
                "Prepare creative variations"
            ]
        }
    
    def _calculate_scenario_confidence(self, performance_data: Dict[str, Any]) -> float:
        """Calculate confidence in projections"""
        # Based on data quality
        conversions = performance_data.get("conversions", 0)
        spend = performance_data.get("spend", 0)
        
        if conversions > 100 and spend > 1000:
            return 85.0
        elif conversions > 50 and spend > 500:
            return 70.0
        else:
            return 50.0
    
    def _analyze_auction_dynamics(
        self, 
        current_bid: float, 
        new_bids: List[float],
        current_performance: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Analyze auction dynamics"""
        avg_new_bid = statistics.mean(new_bids)
        bid_change = ((avg_new_bid - current_bid) / current_bid * 100) if current_bid > 0 else 0
        
        return {
            "current_bid": current_bid,
            "avg_proposed_bid": avg_new_bid,
            "bid_change_percentage": bid_change,
            "auction_competitiveness": "high" if current_bid > 2.0 else "medium" if current_bid > 1.0 else "low",
            "win_rate_impact": "increases" if bid_change > 0 else "decreases"
        }
    
    def _calculate_reach_projections(
        self, 
        current_performance: Dict[str, Any], 
        expansion_strategies: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """Calculate reach projections"""
        current_reach = current_performance.get("reach", 50000)
        
        projections = {}
        for strategy in expansion_strategies:
            strategy_type = strategy.get("type", "lookalike")
            if "lookalike_1" in strategy_type:
                projected_reach = current_reach * 2
            elif "lookalike" in strategy_type:
                projected_reach = current_reach * 4
            elif "interest" in strategy_type:
                projected_reach = current_reach * 2.5
            else:
                projected_reach = current_reach * 6
            
            projections[strategy_type] = {
                "projected_reach": projected_reach,
                "reach_increase_percentage": ((projected_reach - current_reach) / current_reach * 100)
            }
        
        return projections
    
    def _analyze_quality_volume_tradeoff(self, scenarios: List[ScenarioOutcome]) -> Dict[str, Any]:
        """Analyze quality vs. volume tradeoff"""
        return {
            "insight": "Higher reach typically means lower quality",
            "recommendation": "Balance reach expansion with quality retention",
            "optimal_balance": "Lookalike 1-2% offers best quality/volume ratio"
        }
    
    def _recommend_expansion_approach(
        self, 
        scenarios: List[ScenarioOutcome], 
        risk_tolerance: str
    ) -> str:
        """Recommend expansion approach"""
        if risk_tolerance == "conservative":
            return "Start with 1% lookalike, monitor for 1 week before expanding"
        elif risk_tolerance == "moderate":
            return "Launch 1-2% lookalike simultaneously, expand after validation"
        else:  # aggressive
            return "Multi-tier launch: 1%, 2-5%, and interest expansion in parallel"
    
    async def _get_creative_performance_history(
        self, 
        entity_id: str, 
        time_range: Dict[str, str]
    ) -> Dict[str, Any]:
        """Get creative performance history"""
        # Simplified - in production would fetch actual creative data
        return {
            "conversions": 250,
            "ctr": 0.02,
            "roas": 3.2,
            "frequency": 3.5,
            "days_running": 30
        }
    
    def _analyze_creative_fatigue(self, creative_performance: Dict[str, Any]) -> Dict[str, Any]:
        """Analyze creative fatigue"""
        frequency = creative_performance.get("frequency", 2.0)
        days_running = creative_performance.get("days_running", 0)
        
        # Calculate fatigue level
        if frequency > 4.0 or days_running > 45:
            fatigue_level = 80
            fatigue_status = "high"
        elif frequency > 3.0 or days_running > 30:
            fatigue_level = 50
            fatigue_status = "medium"
        else:
            fatigue_level = 20
            fatigue_status = "low"
        
        return {
            "fatigue_level": fatigue_level,
            "fatigue_status": fatigue_status,
            "frequency": frequency,
            "days_running": days_running,
            "recommendation": "Refresh immediately" if fatigue_level > 70 else "Plan refresh soon" if fatigue_level > 40 else "No immediate action needed"
        }
    
    def _calculate_expected_lift(
        self, 
        fatigue_analysis: Dict[str, Any], 
        scenarios: List[ScenarioOutcome]
    ) -> Dict[str, float]:
        """Calculate expected lift from refresh"""
        fatigue_level = fatigue_analysis.get("fatigue_level", 0)
        
        # Higher fatigue = higher lift potential
        return {
            "conservative_estimate": 10 + fatigue_level * 0.2,
            "expected_estimate": 20 + fatigue_level * 0.3,
            "optimistic_estimate": 30 + fatigue_level * 0.5
        }
    
    def _recommend_refresh_timing(
        self, 
        fatigue_analysis: Dict[str, Any], 
        refresh_strategies: List[Dict[str, Any]]
    ) -> List[str]:
        """Recommend refresh timing"""
        fatigue_level = fatigue_analysis.get("fatigue_level", 0)
        
        if fatigue_level > 70:
            return ["Refresh immediately", "Performance is significantly declining"]
        elif fatigue_level > 40:
            return ["Plan refresh within 1 week", "Fatigue is building"]
        else:
            return ["Schedule refresh in 2-3 weeks", "Proactive refresh recommended"]
    
    async def _get_historical_seasonal_data(
        self, 
        ad_account_id: str, 
        seasonal_period: str
    ) -> Dict[str, Any]:
        """Get historical seasonal data"""
        # Simplified - in production would fetch actual historical data
        return {
            "avg_conversions": 250,
            "avg_spend": 5000,
            "avg_roas": 3.2,
            "traffic_pattern": "spike_during_period"
        }
    
    def _calculate_capacity_requirements(
        self, 
        historical_data: Dict[str, Any], 
        expected_increase: float
    ) -> Dict[str, Any]:
        """Calculate capacity requirements"""
        base_capacity = historical_data.get("avg_conversions", 250)
        required_capacity = base_capacity * (1 + expected_increase / 100)
        
        return {
            "current_capacity": base_capacity,
            "required_capacity": required_capacity,
            "capacity_gap": required_capacity - base_capacity,
            "recommendation": f"Increase capacity by {expected_increase}% to meet demand"
        }
    
    def _create_budget_scaling_plan(
        self, 
        historical_data: Dict[str, Any], 
        expected_increase: float,
        scenarios: List[ScenarioOutcome]
    ) -> Dict[str, Any]:
        """Create budget scaling plan"""
        base_budget = historical_data.get("avg_spend", 5000)
        
        return {
            "pre_season": {
                "weeks_before": 2,
                "budget": base_budget * 1.2,
                "purpose": "Build momentum"
            },
            "peak_season": {
                "duration": "1-2 weeks",
                "budget": base_budget * 2.5,
                "purpose": "Maximize capture"
            },
            "post_season": {
                "weeks_after": 1,
                "budget": base_budget * 1.3,
                "purpose": "Sustain momentum"
            }
        }
    
    def _identify_seasonal_risks(
        self, 
        historical_data: Dict[str, Any], 
        expected_increase: float
    ) -> List[str]:
        """Identify seasonal risks"""
        return [
            "Increased competition during peak period",
            "Higher CPMs due to demand",
            "Potential creative fatigue from high frequency",
            "Budget constraints if traffic exceeds expectations",
            "Inventory limitations for e-commerce"
        ]
    
    def _create_preparation_timeline(self, seasonal_period: str) -> Dict[str, List[str]]:
        """Create preparation timeline"""
        return {
            "4_weeks_before": [
                "Analyze historical data",
                "Plan budget increases",
                "Develop new creative"
            ],
            "2_weeks_before": [
                "Launch new campaigns",
                "Test creative variations",
                "Increase budgets 20%"
            ],
            "1_week_before": [
                "Scale winning campaigns",
                "Increase budgets to peak levels",
                "Setup monitoring alerts"
            ],
            "during_peak": [
                "Monitor hourly",
                "Make real-time adjustments",
                "Ensure creative freshness"
            ]
        }
    
    def _create_comparison_matrix(
        self, 
        strategy_projections: List[ScenarioOutcome], 
        evaluation_criteria: List[str]
    ) -> Dict[str, Dict[str, Any]]:
        """Create comparison matrix"""
        matrix = {}
        
        for projection in strategy_projections:
            strategy_name = projection.scenario_name
            matrix[strategy_name] = {}
            
            for criterion in evaluation_criteria:
                if criterion in projection.projected_metrics:
                    matrix[strategy_name][criterion] = projection.projected_metrics[criterion]
                else:
                    matrix[strategy_name][criterion] = "N/A"
        
        return matrix
    
    def _rank_strategies(
        self, 
        strategy_projections: List[ScenarioOutcome], 
        evaluation_criteria: List[str]
    ) -> List[Dict[str, Any]]:
        """Rank strategies"""
        # Simple ranking by ROAS (primary criterion)
        ranked = sorted(
            strategy_projections,
            key=lambda s: s.projected_metrics.get("roas", 0),
            reverse=True
        )
        
        return [
            {
                "rank": i + 1,
                "strategy": s.scenario_name,
                "score": s.projected_metrics.get("roas", 0),
                "probability": s.probability
            }
            for i, s in enumerate(ranked)
        ]
    
    def _recommend_strategy(
        self, 
        ranked_strategies: List[Dict[str, Any]], 
        risk_tolerance: str
    ) -> Dict[str, Any]:
        """Recommend strategy with rationale"""
        if not ranked_strategies:
            return {"strategy": "None", "rationale": "No strategies available"}
        
        # Choose based on risk tolerance
        if risk_tolerance == "conservative":
            # Choose safest option (highest probability)
            best = max(ranked_strategies, key=lambda s: s["probability"])
        else:
            # Choose highest performer
            best = ranked_strategies[0]
        
        return {
            "recommended_strategy": best["strategy"],
            "rank": best["rank"],
            "score": best["score"],
            "rationale": f"Best balance of performance and risk for {risk_tolerance} risk tolerance",
            "confidence": best["probability"] * 100
        }
    
    def _assess_implementation_difficulty(self, strategies: List[Dict[str, Any]]) -> Dict[str, str]:
        """Assess implementation difficulty"""
        difficulties = {}
        
        for strategy in strategies:
            strategy_name = strategy.get("name", "Strategy")
            changes = strategy.get("changes", {})
            
            if len(changes) > 3:
                difficulties[strategy_name] = "complex"
            elif len(changes) > 1:
                difficulties[strategy_name] = "moderate"
            else:
                difficulties[strategy_name] = "simple"
        
        return difficulties


# Global scenario planning engine instance
_scenario_engine: Optional[ScenarioPlanningEngine] = None


def get_scenario_engine() -> ScenarioPlanningEngine:
    """Get the global ScenarioPlanningEngine instance"""
    global _scenario_engine
    if _scenario_engine is None:
        from .meta_client import get_client
        _scenario_engine = ScenarioPlanningEngine(get_client())
    return _scenario_engine

