"""
Budget Optimization Engine

Advanced budget allocation and optimization for enterprise advertisers.
Portfolio-level budget optimization, marginal ROAS calculations, and pacing control.
"""

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

from .base.engine import BaseEngine
from .errors import EngineError as MetaAPIError
from .logging import get_logger

logger = get_logger(__name__)


class BudgetOptimizationEngine(BaseEngine):
    """Advanced budget optimization engine.
    
    Capabilities:
    - Portfolio budget optimization
    - Marginal ROAS calculation
    - Automatic pacing control
    - Campaign ceiling detection
    - Underdelivery rescue
    """
    
    async def initialize(self) -> None:
        """Initialize budget optimization engine."""
        logger.info("budget_optimization_engine_initialized")
        self._initialized = True
    
    async def shutdown(self) -> None:
        """Shutdown budget optimization engine."""
        logger.info("budget_optimization_engine_shutdown")
        self._shutdown = True
    
    async def optimize_portfolio_budget(
        self,
        ad_account_id: str,
        campaign_ids: List[str],
        total_budget: float,
        optimization_goal: str = "roas",
        constraints: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """Optimize budget allocation across campaign portfolio.
        
        Uses performance data to allocate budget optimally across campaigns.
        
        Args:
            ad_account_id: Meta ad account ID
            campaign_ids: List of campaign IDs to optimize
            total_budget: Total budget to allocate
            optimization_goal: 'roas', 'conversions', or 'reach'
            constraints: Min/max budget constraints per campaign
        
        Returns:
            Optimal budget allocation recommendations
        """
        await self._ensure_initialized()
        
        logger.info("optimizing_portfolio_budget", campaigns=len(campaign_ids))
        
        try:
            # Get performance data for all campaigns
            campaign_performance = []
            
            for campaign_id in campaign_ids:
                insights = await self.client.get_insights(
                    object_id=campaign_id,
                    level="campaign",
                    fields=["spend", "actions", "action_values", "impressions", "reach"],
                    time_range={
                        "since": (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"),
                        "until": datetime.now().strftime("%Y-%m-%d")
                    },
                    action_breakdowns=["action_type"]
                )
                
                data = insights.get("data", [])
                if data:
                    insight = data[0]
                    spend = float(insight.get("spend", 0))
                    
                    # Calculate metrics
                    revenue = 0
                    conversions = 0
                    
                    for action_value in insight.get("action_values", []):
                        if action_value.get("action_type") in ["purchase", "omni_purchase"]:
                            revenue += float(action_value.get("value", 0))
                    
                    for action in insight.get("actions", []):
                        if action.get("action_type") in ["purchase", "omni_purchase"]:
                            conversions += int(action.get("value", 0))
                    
                    roas = (revenue / spend) if spend > 0 else 0
                    cpa = (spend / conversions) if conversions > 0 else 0
                    
                    campaign_performance.append({
                        "campaign_id": campaign_id,
                        "current_spend": spend,
                        "revenue": revenue,
                        "conversions": conversions,
                        "roas": roas,
                        "cpa": cpa,
                        "impressions": int(insight.get("impressions", 0)),
                        "reach": int(insight.get("reach", 0))
                    })
            
            if not campaign_performance:
                return {
                    "error": "No performance data available for campaigns",
                    "campaign_ids": campaign_ids
                }
            
            # Sort campaigns by optimization goal
            if optimization_goal == "roas":
                campaign_performance.sort(key=lambda x: x["roas"], reverse=True)
                metric_name = "ROAS"
            elif optimization_goal == "conversions":
                # Sort by CPA (lower is better)
                campaign_performance.sort(key=lambda x: x["cpa"] if x["cpa"] > 0 else float('inf'))
                metric_name = "CPA"
            else:  # reach
                # Sort by CPM efficiency
                campaign_performance.sort(key=lambda x: x["impressions"] / x["current_spend"] if x["current_spend"] > 0 else 0, reverse=True)
                metric_name = "CPM Efficiency"
            
            # Calculate optimal allocation
            # Simple proportional allocation based on performance
            total_weight = 0
            for campaign in campaign_performance:
                if optimization_goal == "roas":
                    weight = campaign["roas"]
                elif optimization_goal == "conversions":
                    weight = 1 / campaign["cpa"] if campaign["cpa"] > 0 else 0
                else:
                    weight = campaign["impressions"] / campaign["current_spend"] if campaign["current_spend"] > 0 else 0
                
                campaign["weight"] = weight
                total_weight += weight
            
            # Allocate budget proportionally
            allocations = []
            total_allocated = 0
            
            for campaign in campaign_performance:
                if total_weight > 0:
                    proportion = campaign["weight"] / total_weight
                    allocated_budget = total_budget * proportion
                    
                    # Apply constraints if provided
                    if constraints:
                        min_budget = constraints.get(campaign["campaign_id"], {}).get("min", 0)
                        max_budget = constraints.get(campaign["campaign_id"], {}).get("max", float('inf'))
                        allocated_budget = max(min_budget, min(max_budget, allocated_budget))
                    
                    budget_change = allocated_budget - campaign["current_spend"]
                    budget_change_pct = (budget_change / campaign["current_spend"] * 100) if campaign["current_spend"] > 0 else 0
                    
                    allocations.append({
                        "campaign_id": campaign["campaign_id"],
                        "current_budget": round(campaign["current_spend"], 2),
                        "recommended_budget": round(allocated_budget, 2),
                        "change": round(budget_change, 2),
                        "change_percentage": round(budget_change_pct, 2),
                        "performance_metric": round(campaign[optimization_goal] if optimization_goal in campaign else 0, 2),
                        "priority": "increase" if budget_change > 0 else "decrease" if budget_change < 0 else "maintain"
                    })
                    
                    total_allocated += allocated_budget
            
            # Calculate expected impact
            total_current_revenue = sum(c["revenue"] for c in campaign_performance)
            expected_revenue_increase = total_budget * (campaign_performance[0]["roas"] if campaign_performance else 0)
            
            optimization_result = {
                "ad_account_id": ad_account_id,
                "optimization_goal": optimization_goal,
                "metric_optimized": metric_name,
                "total_budget": total_budget,
                "total_allocated": round(total_allocated, 2),
                "campaigns_analyzed": len(campaign_performance),
                "allocations": allocations,
                "expected_impact": {
                    "current_performance": {
                        "total_revenue": round(total_current_revenue, 2),
                        "average_roas": round(sum(c["roas"] for c in campaign_performance) / len(campaign_performance), 2)
                    },
                    "projected_improvement": {
                        "estimated_revenue_increase": round(expected_revenue_increase - total_current_revenue, 2),
                        "improvement_percentage": round(((expected_revenue_increase - total_current_revenue) / total_current_revenue * 100), 2) if total_current_revenue > 0 else 0
                    }
                },
                "recommendations": []
            }
            
            # Generate recommendations
            high_performers = [a for a in allocations if a["priority"] == "increase"]
            if high_performers:
                optimization_result["recommendations"].append({
                    "action": f"Increase budget for {len(high_performers)} high-performing campaigns",
                    "campaigns": [h["campaign_id"] for h in high_performers[:3]],
                    "estimated_impact": f"+{optimization_result['expected_impact']['projected_improvement']['improvement_percentage']:.0f}% revenue"
                })
            
            low_performers = [a for a in allocations if a["priority"] == "decrease"]
            if low_performers:
                optimization_result["recommendations"].append({
                    "action": f"Reduce budget for {len(low_performers)} underperforming campaigns",
                    "campaigns": [campaign["campaign_id"] for campaign in low_performers[:3]],
                    "reallocate_to": high_performers[0]["campaign_id"] if high_performers else None
                })
            
            logger.info("portfolio_budget_optimized", total_budget=total_budget, campaigns=len(allocations))
            return optimization_result
            
        except Exception as e:
            logger.error("portfolio_budget_optimization_failed", error=str(e))
            raise MetaAPIError(f"Portfolio budget optimization failed: {str(e)}")
    
    async def calculate_marginal_roas(
        self,
        ad_account_id: str,
        campaign_id: str,
        budget_increments: List[float] = [1000, 2000, 5000, 10000]
    ) -> Dict[str, Any]:
        """Calculate marginal ROAS at different budget levels.
        
        Estimates incremental return for budget increases.
        
        Args:
            ad_account_id: Meta ad account ID
            campaign_id: Campaign ID to analyze
            budget_increments: Budget increase amounts to test
        
        Returns:
            Marginal ROAS analysis
        """
        await self._ensure_initialized()
        
        logger.info("calculating_marginal_roas", campaign_id=campaign_id)
        
        try:
            # Get historical performance at different spend levels
            insights = await self.client.get_insights(
                object_id=campaign_id,
                level="campaign",
                fields=["spend", "actions", "action_values", "impressions", "reach"],
                time_increment=1,
                time_range={
                    "since": (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d"),
                    "until": datetime.now().strftime("%Y-%m-%d")
                },
                action_breakdowns=["action_type"]
            )
            
            data = insights.get("data", [])
            
            if len(data) < 7:
                return {
                    "campaign_id": campaign_id,
                    "error": "Insufficient data for marginal ROAS calculation (need 7+ days)"
                }
            
            # Calculate daily performance
            daily_performance = []
            for insight in data:
                spend = float(insight.get("spend", 0))
                revenue = 0
                
                for action_value in insight.get("action_values", []):
                    if action_value.get("action_type") in ["purchase", "omni_purchase"]:
                        revenue += float(action_value.get("value", 0))
                
                if spend > 0:
                    daily_performance.append({
                        "date": insight.get("date_start", ""),
                        "spend": spend,
                        "revenue": revenue,
                        "roas": revenue / spend
                    })
            
            # Sort by spend to analyze marginal returns
            daily_performance.sort(key=lambda x: x["spend"])
            
            # Calculate current performance
            current_avg_spend = sum(d["spend"] for d in daily_performance) / len(daily_performance)
            current_avg_revenue = sum(d["revenue"] for d in daily_performance) / len(daily_performance)
            current_roas = current_avg_revenue / current_avg_spend if current_avg_spend > 0 else 0
            
            # Estimate marginal ROAS for each increment
            # Use high-spend days to estimate performance at higher budgets
            high_spend_days = [d for d in daily_performance if d["spend"] > current_avg_spend]
            low_spend_days = [d for d in daily_performance if d["spend"] <= current_avg_spend]
            
            avg_roas_high_spend = sum(d["roas"] for d in high_spend_days) / len(high_spend_days) if high_spend_days else current_roas
            avg_roas_low_spend = sum(d["roas"] for d in low_spend_days) / len(low_spend_days) if low_spend_days else current_roas
            
            # Estimate diminishing returns rate
            diminishing_rate = 0.9 if avg_roas_high_spend < avg_roas_low_spend else 0.95
            
            # Calculate marginal ROAS for each increment
            marginal_analysis = []
            cumulative_spend = current_avg_spend
            
            for increment in budget_increments:
                # Estimate ROAS at this budget level (with diminishing returns)
                scale_factor = (cumulative_spend + increment) / current_avg_spend
                estimated_roas = current_roas * (diminishing_rate ** (scale_factor - 1))
                
                marginal_revenue = increment * estimated_roas
                marginal_profit = marginal_revenue - increment
                marginal_roi = (marginal_profit / increment * 100) if increment > 0 else 0
                
                marginal_analysis.append({
                    "budget_increase": increment,
                    "new_total_budget": round(cumulative_spend + increment, 2),
                    "estimated_marginal_roas": round(estimated_roas, 2),
                    "estimated_marginal_revenue": round(marginal_revenue, 2),
                    "marginal_profit": round(marginal_profit, 2),
                    "marginal_roi_percentage": round(marginal_roi, 2),
                    "recommendation": "increase" if marginal_roi > 50 else "consider" if marginal_roi > 0 else "do_not_increase"
                })
            
            result = {
                "campaign_id": campaign_id,
                "current_performance": {
                    "avg_daily_spend": round(current_avg_spend, 2),
                    "avg_daily_revenue": round(current_avg_revenue, 2),
                    "current_roas": round(current_roas, 2)
                },
                "marginal_analysis": marginal_analysis,
                "recommendations": [],
                "analysis_notes": f"Based on {len(daily_performance)} days of data with diminishing returns factor {diminishing_rate}"
            }
            
            # Generate recommendations
            for analysis in marginal_analysis:
                if analysis["recommendation"] == "increase":
                    result["recommendations"].append({
                        "budget_increase": analysis["budget_increase"],
                        "action": f"Recommend increasing budget by ${analysis['budget_increase']:.0f}",
                        "expected_return": f"${analysis['estimated_marginal_revenue']:.0f} additional revenue",
                        "roi": f"{analysis['marginal_roi_percentage']:.0f}%"
                    })
                    break  # Only recommend the first viable increase
            
            if not result["recommendations"]:
                result["recommendations"].append({
                    "action": "Do not increase budget",
                    "reason": "Marginal returns are too low at current performance levels"
                })
            
            logger.info("marginal_roas_calculated", current_roas=current_roas)
            return result
            
        except Exception as e:
            logger.error("marginal_roas_calculation_failed", error=str(e))
            raise MetaAPIError(f"Marginal ROAS calculation failed: {str(e)}")
    
    async def autopilot_pacing(
        self,
        ad_account_id: str,
        campaign_id: str,
        daily_budget: float,
        pacing_strategy: str = "even"
    ) -> Dict[str, Any]:
        """Auto-adjust budget pacing throughout the day.
        
        Args:
            ad_account_id: Meta ad account ID
            campaign_id: Campaign ID
            daily_budget: Target daily budget
            pacing_strategy: 'even', 'front_load', or 'back_load'
        
        Returns:
            Pacing adjustment recommendations
        """
        await self._ensure_initialized()
        
        logger.info("autopilot_pacing", campaign_id=campaign_id, strategy=pacing_strategy)
        
        try:
            # Get today's hourly spend
            today = datetime.now().strftime("%Y-%m-%d")
            insights = await self.client.get_insights(
                object_id=campaign_id,
                level="campaign",
                fields=["spend"],
                breakdowns=["hourly_stats_aggregated_by_advertiser_time_zone"],
                time_range={"since": today, "until": today}
            )
            
            data = insights.get("data", [])
            current_hour = datetime.now().hour
            
            # Calculate current spend
            current_spend = sum(float(d.get("spend", 0)) for d in data)
            hours_remaining = 24 - current_hour
            
            # Calculate ideal pacing based on strategy
            if pacing_strategy == "even":
                ideal_spend_by_now = (daily_budget / 24) * current_hour
                target_hourly_spend = daily_budget / 24
            elif pacing_strategy == "front_load":
                # Front-load: Spend 60% in first 12 hours
                if current_hour < 12:
                    ideal_spend_by_now = (daily_budget * 0.6 / 12) * current_hour
                    target_hourly_spend = daily_budget * 0.6 / 12
                else:
                    ideal_spend_by_now = (daily_budget * 0.6) + ((daily_budget * 0.4 / 12) * (current_hour - 12))
                    target_hourly_spend = daily_budget * 0.4 / 12
            else:  # back_load
                # Back-load: Spend 40% in first 12 hours, 60% in last 12
                if current_hour < 12:
                    ideal_spend_by_now = (daily_budget * 0.4 / 12) * current_hour
                    target_hourly_spend = daily_budget * 0.4 / 12
                else:
                    ideal_spend_by_now = (daily_budget * 0.4) + ((daily_budget * 0.6 / 12) * (current_hour - 12))
                    target_hourly_spend = daily_budget * 0.6 / 12
            
            # Calculate pacing status
            spend_variance = current_spend - ideal_spend_by_now
            spend_variance_pct = (spend_variance / ideal_spend_by_now * 100) if ideal_spend_by_now > 0 else 0
            
            # Calculate required hourly spend for rest of day
            remaining_budget = daily_budget - current_spend
            required_hourly_spend = remaining_budget / hours_remaining if hours_remaining > 0 else 0
            
            pacing_result = {
                "campaign_id": campaign_id,
                "pacing_strategy": pacing_strategy,
                "current_hour": current_hour,
                "hours_remaining": hours_remaining,
                "budget_status": {
                    "daily_budget": daily_budget,
                    "current_spend": round(current_spend, 2),
                    "remaining_budget": round(remaining_budget, 2),
                    "ideal_spend_by_now": round(ideal_spend_by_now, 2),
                    "spend_variance": round(spend_variance, 2),
                    "spend_variance_percentage": round(spend_variance_pct, 2)
                },
                "pacing_status": "on_track",
                "adjustments_needed": [],
                "recommendations": []
            }
            
            # Determine pacing status and adjustments
            if spend_variance_pct > 20:
                pacing_result["pacing_status"] = "overpacing"
                pacing_result["adjustments_needed"].append({
                    "action": "Reduce hourly spend rate",
                    "from": round(target_hourly_spend, 2),
                    "to": round(required_hourly_spend, 2),
                    "reason": f"Overpacing by {spend_variance_pct:.0f}%"
                })
                pacing_result["recommendations"].append({
                    "priority": "high",
                    "action": "Reduce bid or narrow targeting to slow down spend",
                    "estimated_impact": f"Save ${abs(spend_variance):.0f}"
                })
            elif spend_variance_pct < -20:
                pacing_result["pacing_status"] = "underpacing"
                pacing_result["adjustments_needed"].append({
                    "action": "Increase hourly spend rate",
                    "from": round(target_hourly_spend, 2),
                    "to": round(required_hourly_spend, 2),
                    "reason": f"Underpacing by {abs(spend_variance_pct):.0f}%"
                })
                pacing_result["recommendations"].append({
                    "priority": "medium",
                    "action": "Increase bid or broaden targeting to accelerate spend",
                    "estimated_impact": f"Utilize additional ${abs(spend_variance):.0f}"
                })
            else:
                pacing_result["recommendations"].append({
                    "priority": "low",
                    "action": "Maintain current pacing - on track",
                    "message": "No adjustments needed"
                })
            
            logger.info("pacing_autopilot_complete", status=pacing_result["pacing_status"])
            return pacing_result
            
        except Exception as e:
            logger.error("pacing_autopilot_failed", error=str(e))
            raise MetaAPIError(f"Pacing autopilot failed: {str(e)}")
    
    async def detect_campaign_ceiling(
        self,
        ad_account_id: str,
        campaign_id: str
    ) -> Dict[str, Any]:
        """Detect campaign spending ceiling (maximum viable budget).
        
        Args:
            ad_account_id: Meta ad account ID
            campaign_id: Campaign ID
        
        Returns:
            Campaign ceiling analysis
        """
        await self._ensure_initialized()
        
        logger.info("detecting_campaign_ceiling", campaign_id=campaign_id)
        
        try:
            # Get last 30 days with daily breakdown
            insights = await self.client.get_insights(
                object_id=campaign_id,
                level="campaign",
                fields=["spend", "impressions", "reach", "frequency"],
                time_increment=1,
                time_range={
                    "since": (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d"),
                    "until": datetime.now().strftime("%Y-%m-%d")
                }
            )
            
            data = insights.get("data", [])
            
            if len(data) < 14:
                return {
                    "campaign_id": campaign_id,
                    "error": "Insufficient data (need 14+ days)"
                }
            
            # Sort by spend to find maximum
            daily_data = [{
                "date": d.get("date_start", ""),
                "spend": float(d.get("spend", 0)),
                "impressions": int(d.get("impressions", 0)),
                "reach": int(d.get("reach", 0)),
                "frequency": float(d.get("frequency", 0))
            } for d in data]
            
            daily_data.sort(key=lambda x: x["spend"], reverse=True)
            
            # Find maximum sustainable spend
            top_spend_days = daily_data[:5]
            max_daily_spend = max(d["spend"] for d in daily_data)
            avg_top_spend = sum(d["spend"] for d in top_spend_days) / len(top_spend_days)
            
            # Check for frequency saturation
            avg_frequency_high_spend = sum(d["frequency"] for d in top_spend_days) / len(top_spend_days)
            
            # Detect ceiling
            ceiling_detected = False
            ceiling_amount = None
            ceiling_reason = []
            
            # Check if spend plateaued
            recent_spend = [d["spend"] for d in daily_data if d["date"] >= (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d")]
            avg_recent_spend = sum(recent_spend) / len(recent_spend) if recent_spend else 0
            
            if avg_recent_spend >= max_daily_spend * 0.9:
                ceiling_detected = True
                ceiling_amount = max_daily_spend
                ceiling_reason.append(f"Campaign consistently spending near maximum (${max_daily_spend:.0f}/day)")
            
            if avg_frequency_high_spend > 4:
                ceiling_detected = True
                if not ceiling_amount:
                    ceiling_amount = avg_top_spend
                ceiling_reason.append(f"High frequency ({avg_frequency_high_spend:.1f}x) indicates audience saturation")
            
            # Calculate headroom
            if ceiling_amount:
                current_avg_spend = sum(d["spend"] for d in daily_data[-7:]) / 7
                headroom = ceiling_amount - current_avg_spend
                headroom_pct = (headroom / ceiling_amount * 100) if ceiling_amount > 0 else 0
            else:
                current_avg_spend = sum(d["spend"] for d in daily_data) / len(daily_data)
                headroom = None
                headroom_pct = None
            
            result = {
                "campaign_id": campaign_id,
                "ceiling_detected": ceiling_detected,
                "ceiling_amount": round(ceiling_amount, 2) if ceiling_amount else None,
                "ceiling_reasons": ceiling_reason,
                "current_performance": {
                    "max_daily_spend": round(max_daily_spend, 2),
                    "avg_daily_spend": round(current_avg_spend, 2),
                    "avg_top_5_days_spend": round(avg_top_spend, 2)
                },
                "headroom": {
                    "additional_budget_capacity": round(headroom, 2) if headroom else "Unknown",
                    "headroom_percentage": round(headroom_pct, 2) if headroom_pct else "Unknown"
                },
                "recommendations": []
            }
            
            if ceiling_detected:
                result["recommendations"].append({
                    "priority": "high",
                    "action": f"Campaign ceiling reached at ~${ceiling_amount:.0f}/day",
                    "suggestions": [
                        "Expand audience targeting",
                        "Create lookalike audiences",
                        "Test new geographic markets",
                        "Consider launching duplicate campaign with different audience"
                    ]
                })
            else:
                result["recommendations"].append({
                    "priority": "low",
                    "action": "No ceiling detected - room for growth",
                    "suggestions": [
                        f"Consider testing budget increase to ${max_daily_spend * 1.2:.0f}/day"
                    ]
                })
            
            logger.info("campaign_ceiling_detected", ceiling=ceiling_detected, amount=ceiling_amount)
            return result
            
        except Exception as e:
            logger.error("campaign_ceiling_detection_failed", error=str(e))
            raise MetaAPIError(f"Campaign ceiling detection failed: {str(e)}")
    
    async def rescue_underdelivering_campaigns(
        self,
        ad_account_id: str,
        campaign_ids: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """Detect and rescue campaigns not spending their budget.
        
        Args:
            ad_account_id: Meta ad account ID
            campaign_ids: Specific campaigns to check (optional, checks all if None)
        
        Returns:
            Underdelivery analysis with rescue recommendations
        """
        await self._ensure_initialized()
        
        logger.info("rescuing_underdelivering_campaigns", ad_account_id=ad_account_id)
        
        try:
            # Get all active campaigns if not specified
            if not campaign_ids:
                campaigns = await self.client.get(
                    f"/{ad_account_id}/campaigns",
                    params={"fields": "id,name,status,daily_budget,lifetime_budget", "limit": 100}
                )
                campaign_ids = [c["id"] for c in campaigns.get("data", []) if c.get("status") == "ACTIVE"]
            
            underdelivering = []
            
            for campaign_id in campaign_ids:
                # Get campaign details
                campaign_data = await self.client.get(
                    f"/{campaign_id}",
                    params={"fields": "id,name,daily_budget,lifetime_budget,effective_status"}
                )
                
                daily_budget = float(campaign_data.get("daily_budget", 0)) / 100 if campaign_data.get("daily_budget") else None
                
                if not daily_budget:
                    continue  # Skip lifetime budget campaigns for this analysis
                
                # Get today's spend
                today = datetime.now().strftime("%Y-%m-%d")
                insights = await self.client.get_insights(
                    object_id=campaign_id,
                    level="campaign",
                    fields=["spend"],
                    time_range={"since": today, "until": today}
                )
                
                data = insights.get("data", [])
                today_spend = sum(float(d.get("spend", 0)) for d in data)
                
                # Calculate utilization
                utilization_pct = (today_spend / daily_budget * 100) if daily_budget > 0 else 0
                
                # Detect underdelivery (< 80% of budget spent)
                current_hour = datetime.now().hour
                expected_spend = (daily_budget / 24) * current_hour
                
                if today_spend < expected_spend * 0.8 and current_hour > 6:  # Only check after 6am
                    # Get delivery insights to diagnose
                    delivery_status = campaign_data.get("effective_status", "UNKNOWN")
                    
                    underdelivering.append({
                        "campaign_id": campaign_id,
                        "campaign_name": campaign_data.get("name", "Unknown"),
                        "daily_budget": round(daily_budget, 2),
                        "today_spend": round(today_spend, 2),
                        "expected_spend": round(expected_spend, 2),
                        "utilization_percentage": round(utilization_pct, 2),
                        "shortfall": round(expected_spend - today_spend, 2),
                        "delivery_status": delivery_status,
                        "rescue_actions": []
                    })
            
            # Generate rescue recommendations
            for campaign in underdelivering:
                if campaign["utilization_percentage"] < 50:
                    campaign["rescue_actions"].append({
                        "priority": "critical",
                        "action": "Increase bid by 20-30%",
                        "reason": "Severely underpacing - likely losing auctions"
                    })
                    campaign["rescue_actions"].append({
                        "priority": "high",
                        "action": "Broaden audience targeting",
                        "reason": "May be too narrow to deliver budget"
                    })
                elif campaign["utilization_percentage"] < 80:
                    campaign["rescue_actions"].append({
                        "priority": "medium",
                        "action": "Increase bid by 10-15%",
                        "reason": "Moderate underpacing"
                    })
                    campaign["rescue_actions"].append({
                        "priority": "medium",
                        "action": "Check placement restrictions",
                        "reason": "May be limiting delivery"
                    })
            
            result = {
                "ad_account_id": ad_account_id,
                "campaigns_analyzed": len(campaign_ids),
                "underdelivering_count": len(underdelivering),
                "underdelivering_campaigns": underdelivering,
                "total_budget_at_risk": round(sum(c["shortfall"] for c in underdelivering), 2),
                "summary": {
                    "critical": len([c for c in underdelivering if c["utilization_percentage"] < 50]),
                    "moderate": len([c for c in underdelivering if 50 <= c["utilization_percentage"] < 80])
                }
            }
            
            logger.info("underdelivering_campaigns_rescued", underdelivering=len(underdelivering))
            return result
            
        except Exception as e:
            logger.error("underdelivery_rescue_failed", error=str(e))
            raise MetaAPIError(f"Underdelivery rescue failed: {str(e)}")

