"""
Validation & Preview Tools for Meta Ads MCP Server

This module provides tools to help LLMs validate actions before execution
and preview the impact of changes to avoid costly mistakes.
"""

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

from .meta_client import MetaClient
from .schemas import (
    ValidateBudgetChangeRequest,
    ValidateTargetingRequest,
    ValidateCreativeRequest,
    ValidateCampaignStructureRequest,
    PreviewBudgetImpactRequest,
    PreviewBidImpactRequest,
    ValidateBudgetChangeResponse,
    ValidateTargetingResponse,
    ValidateCreativeResponse,
    ValidateCampaignStructureResponse,
    PreviewBudgetImpactResponse,
    PreviewBidImpactResponse,
    BudgetValidation,
    TargetingValidation,
    CreativeValidation,
    CampaignStructureValidation,
    ImpactAnalysis,
)
from .logging import get_logger

logger = get_logger(__name__)


@dataclass
class ValidationContext:
    """Context for validation operations"""
    ad_account_id: str
    entity_id: str
    entity_type: str
    current_data: Dict[str, Any]
    proposed_changes: Dict[str, Any]


class ValidationEngine:
    """Handles validation and preview operations for Meta Ads"""
    
    def __init__(self, client: MetaClient):
        self.client = client
    
    async def validate_budget_change(
        self, 
        request: ValidateBudgetChangeRequest
    ) -> ValidateBudgetChangeResponse:
        """Validate budget change won't violate limits or cause issues"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes={"budget": request.new_budget}
            )
            
            # Get current budget information
            current_budget = await self._get_current_budget(context)
            
            # Validate the budget change
            validation_result = await self._validate_budget_change_logic(
                current_budget, request.new_budget, request.budget_type
            )
            
            return ValidateBudgetChangeResponse(
                validation_result=validation_result,
                current_budget=current_budget,
                proposed_budget=request.new_budget,
                budget_type=request.budget_type,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error validating budget change: {e}")
            raise
    
    async def validate_targeting(
        self, 
        request: ValidateTargetingRequest
    ) -> ValidateTargetingResponse:
        """Validate targeting configuration for issues"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes=request.targeting_config
            )
            
            # Get current targeting
            current_targeting = await self._get_current_targeting(context)
            
            # Validate targeting configuration
            validation_result = await self._validate_targeting_logic(
                current_targeting, request.targeting_config
            )
            
            return ValidateTargetingResponse(
                validation_result=validation_result,
                current_targeting=current_targeting,
                proposed_targeting=request.targeting_config,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error validating targeting: {e}")
            raise
    
    async def validate_creative(
        self, 
        request: ValidateCreativeRequest
    ) -> ValidateCreativeResponse:
        """Validate creative specifications and requirements"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes=request.creative_config
            )
            
            # Get current creative information
            current_creative = await self._get_current_creative(context)
            
            # Validate creative configuration
            validation_result = await self._validate_creative_logic(
                current_creative, request.creative_config
            )
            
            return ValidateCreativeResponse(
                validation_result=validation_result,
                current_creative=current_creative,
                proposed_creative=request.creative_config,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error validating creative: {e}")
            raise
    
    async def validate_campaign_structure(
        self, 
        request: ValidateCampaignStructureRequest
    ) -> ValidateCampaignStructureResponse:
        """Validate overall campaign structure and setup"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes=request.campaign_config
            )
            
            # Get current campaign structure
            current_structure = await self._get_current_campaign_structure(context)
            
            # Validate campaign structure
            validation_result = await self._validate_campaign_structure_logic(
                current_structure, request.campaign_config
            )
            
            return ValidateCampaignStructureResponse(
                validation_result=validation_result,
                current_structure=current_structure,
                proposed_structure=request.campaign_config,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error validating campaign structure: {e}")
            raise
    
    async def preview_budget_impact(
        self, 
        request: PreviewBudgetImpactRequest
    ) -> PreviewBudgetImpactResponse:
        """Preview the impact of budget changes before applying"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes={"budget": request.new_budget}
            )
            
            # Get current performance data
            current_performance = await self._get_current_performance(context)
            
            # Calculate projected impact
            impact_analysis = await self._calculate_budget_impact(
                current_performance, request.new_budget, request.budget_type
            )
            
            return PreviewBudgetImpactResponse(
                impact_analysis=impact_analysis,
                current_budget=current_performance.get("budget", 0),
                proposed_budget=request.new_budget,
                budget_type=request.budget_type,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error previewing budget impact: {e}")
            raise
    
    async def preview_bid_impact(
        self, 
        request: PreviewBidImpactRequest
    ) -> PreviewBidImpactResponse:
        """Preview the impact of bid changes before applying"""
        try:
            context = ValidationContext(
                ad_account_id=request.ad_account_id,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                current_data={},
                proposed_changes={"bid": request.new_bid}
            )
            
            # Get current performance data
            current_performance = await self._get_current_performance(context)
            
            # Calculate projected impact
            impact_analysis = await self._calculate_bid_impact(
                current_performance, request.new_bid, request.bid_type
            )
            
            return PreviewBidImpactResponse(
                impact_analysis=impact_analysis,
                current_bid=current_performance.get("bid", 0),
                proposed_bid=request.new_bid,
                bid_type=request.bid_type,
                entity_id=request.entity_id,
                entity_type=request.entity_type,
                generated_at=datetime.utcnow()
            )
            
        except Exception as e:
            logger.error(f"Error previewing bid impact: {e}")
            raise
    
    async def _get_current_budget(
        self, 
        context: ValidationContext
    ) -> Dict[str, Any]:
        """Get current budget information for entity"""
        try:
            if context.entity_type == "campaign":
                path = f"{context.entity_id}"
                params = {"fields": "daily_budget,lifetime_budget,budget_remaining"}
            elif context.entity_type == "adset":
                path = f"{context.entity_id}"
                params = {"fields": "daily_budget,lifetime_budget,budget_remaining"}
            else:
                raise ValueError(f"Unsupported entity type for budget: {context.entity_type}")
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response
            
        except Exception as e:
            logger.error(f"Error getting current budget: {e}")
            return {}
    
    async def _get_current_targeting(
        self, 
        context: ValidationContext
    ) -> Dict[str, Any]:
        """Get current targeting configuration"""
        try:
            if context.entity_type == "adset":
                path = f"{context.entity_id}"
                params = {"fields": "targeting,optimization_goal,attribution_spec"}
            else:
                raise ValueError(f"Unsupported entity type for targeting: {context.entity_type}")
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response
            
        except Exception as e:
            logger.error(f"Error getting current targeting: {e}")
            return {}
    
    async def _get_current_creative(
        self, 
        context: ValidationContext
    ) -> Dict[str, Any]:
        """Get current creative information"""
        try:
            if context.entity_type == "ad":
                path = f"{context.entity_id}"
                params = {"fields": "creative,creative_id,name"}
            else:
                raise ValueError(f"Unsupported entity type for creative: {context.entity_type}")
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response
            
        except Exception as e:
            logger.error(f"Error getting current creative: {e}")
            return {}
    
    async def _get_current_campaign_structure(
        self, 
        context: ValidationContext
    ) -> Dict[str, Any]:
        """Get current campaign structure"""
        try:
            if context.entity_type == "campaign":
                path = f"{context.entity_id}"
                params = {"fields": "name,objective,status,special_ad_categories"}
            else:
                raise ValueError(f"Unsupported entity type for campaign structure: {context.entity_type}")
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            return response
            
        except Exception as e:
            logger.error(f"Error getting current campaign structure: {e}")
            return {}
    
    async def _get_current_performance(
        self, 
        context: ValidationContext
    ) -> Dict[str, Any]:
        """Get current performance data for impact analysis"""
        try:
            # Get recent insights
            if context.entity_type == "campaign":
                path = f"{context.entity_id}/insights"
                params = {
                    "fields": "spend,impressions,clicks,conversions,cpm,cpc,ctr,conversion_rate",
                    "time_range": {"since": (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"), "until": datetime.now().strftime("%Y-%m-%d")}
                }
            elif context.entity_type == "adset":
                path = f"{context.entity_id}/insights"
                params = {
                    "fields": "spend,impressions,clicks,conversions,cpm,cpc,ctr,conversion_rate",
                    "time_range": {"since": (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"), "until": datetime.now().strftime("%Y-%m-%d")}
                }
            elif context.entity_type == "ad":
                path = f"{context.entity_id}/insights"
                params = {
                    "fields": "spend,impressions,clicks,conversions,cpm,cpc,ctr,conversion_rate",
                    "time_range": {"since": (datetime.now() - timedelta(days=7)).strftime("%Y-%m-%d"), "until": datetime.now().strftime("%Y-%m-%d")}
                }
            else:
                raise ValueError(f"Unsupported entity type for performance: {context.entity_type}")
            
            response = await self.client.graph_request(
                method="GET",
                path=path,
                params=params
            )
            
            data = response.get("data", [])
            return data[0] if data else {}
            
        except Exception as e:
            logger.error(f"Error getting current performance: {e}")
            return {}
    
    async def _validate_budget_change_logic(
        self, 
        current_budget: Dict[str, Any], 
        new_budget: float, 
        budget_type: str
    ) -> BudgetValidation:
        """Validate budget change logic"""
        try:
            issues = []
            warnings = []
            recommendations = []
            
            # Get current budget values
            current_daily = float(current_budget.get("daily_budget", 0))
            current_lifetime = float(current_budget.get("lifetime_budget", 0))
            budget_remaining = float(current_budget.get("budget_remaining", 0))
            
            # Validate based on budget type
            if budget_type == "daily":
                # Check minimum daily budget
                if new_budget < 1.0:
                    issues.append("Daily budget must be at least $1.00")
                
                # Check for significant changes
                if current_daily > 0:
                    change_percentage = abs(new_budget - current_daily) / current_daily * 100
                    if change_percentage > 75:
                        warnings.append(f"Large budget change: {change_percentage:.1f}% increase/decrease")
                        recommendations.append(
                            "Consider gradual budget changes above 75% to maintain performance stability"
                        )
                
                # Check lifetime budget compatibility
                if current_lifetime > 0 and new_budget * 30 > current_lifetime:
                    warnings.append("Daily budget may exceed lifetime budget within 30 days")
                    recommendations.append("Consider increasing lifetime budget or reducing daily budget")
            
            elif budget_type == "lifetime":
                # Check minimum lifetime budget
                if new_budget < 1.0:
                    issues.append("Lifetime budget must be at least $1.00")
                
                # Check if lifetime budget is sufficient
                if current_daily > 0 and new_budget < current_daily:
                    issues.append("Lifetime budget cannot be less than current daily budget")
                
                # Check remaining budget
                if budget_remaining > 0 and new_budget < budget_remaining:
                    issues.append("Lifetime budget cannot be less than remaining budget")
            
            # Determine overall validation status
            is_valid = len(issues) == 0
            confidence = "high" if len(issues) == 0 and len(warnings) == 0 else "medium" if len(issues) == 0 else "low"
            
            return BudgetValidation(
                is_valid=is_valid,
                confidence=confidence,
                issues=issues,
                warnings=warnings,
                recommendations=recommendations,
                estimated_impact=self._estimate_budget_impact(current_budget, new_budget, budget_type)
            )
            
        except Exception as e:
            logger.error(f"Error validating budget change logic: {e}")
            return BudgetValidation(
                is_valid=False,
                confidence="low",
                issues=[f"Validation error: {str(e)}"],
                warnings=[],
                recommendations=[],
                estimated_impact="unknown"
            )
    
    async def _validate_targeting_logic(
        self, 
        current_targeting: Dict[str, Any], 
        proposed_targeting: Dict[str, Any]
    ) -> TargetingValidation:
        """Validate targeting configuration logic"""
        try:
            issues = []
            warnings = []
            recommendations = []
            
            # Check for required targeting fields
            required_fields = ["geo_locations", "age_min", "age_max"]
            for field in required_fields:
                if field not in proposed_targeting:
                    issues.append(f"Missing required targeting field: {field}")
            
            # Validate age range
            if "age_min" in proposed_targeting and "age_max" in proposed_targeting:
                age_min = proposed_targeting["age_min"]
                age_max = proposed_targeting["age_max"]
                if age_min >= age_max:
                    issues.append("Age minimum must be less than age maximum")
                if age_max - age_min < 2:
                    warnings.append("Very narrow age range may limit reach")
            
            # Validate geo locations
            if "geo_locations" in proposed_targeting:
                geo_locations = proposed_targeting["geo_locations"]
                if not geo_locations.get("countries") and not geo_locations.get("regions"):
                    issues.append("At least one country or region must be specified")
            
            # Check audience size estimation
            estimated_reach = self._estimate_audience_size(proposed_targeting)
            if estimated_reach < 1000:
                warnings.append("Very small estimated audience size may limit performance")
                recommendations.append("Consider expanding targeting criteria")
            elif estimated_reach > 50000000:
                warnings.append("Very large estimated audience size may reduce relevance")
                recommendations.append("Consider adding more specific targeting criteria")
            
            # Determine overall validation status
            is_valid = len(issues) == 0
            confidence = "high" if len(issues) == 0 and len(warnings) == 0 else "medium" if len(issues) == 0 else "low"
            
            return TargetingValidation(
                is_valid=is_valid,
                confidence=confidence,
                issues=issues,
                warnings=warnings,
                recommendations=recommendations,
                estimated_reach=estimated_reach
            )
            
        except Exception as e:
            logger.error(f"Error validating targeting logic: {e}")
            return TargetingValidation(
                is_valid=False,
                confidence="low",
                issues=[f"Validation error: {str(e)}"],
                warnings=[],
                recommendations=[],
                estimated_reach=0
            )
    
    async def _validate_creative_logic(
        self, 
        current_creative: Dict[str, Any], 
        proposed_creative: Dict[str, Any]
    ) -> CreativeValidation:
        """Validate creative configuration logic"""
        try:
            issues = []
            warnings = []
            recommendations = []
            
            # Check for required creative fields
            if "object_story_spec" not in proposed_creative and "creative_id" not in proposed_creative:
                issues.append("Either object_story_spec or creative_id must be provided")
            
            # Validate image specifications
            if "object_story_spec" in proposed_creative:
                story_spec = proposed_creative["object_story_spec"]
                if "page_id" not in story_spec:
                    issues.append("Page ID is required for creative")
                
                if "link_data" in story_spec:
                    link_data = story_spec["link_data"]
                    if "image_hash" not in link_data:
                        warnings.append("Image is recommended for link ads")
                    if "message" not in link_data:
                        warnings.append("Message text is recommended for better engagement")
            
            # Check creative format compliance
            if "object_story_spec" in proposed_creative:
                format_issues = self._validate_creative_format(proposed_creative["object_story_spec"])
                issues.extend(format_issues)
            
            # Determine overall validation status
            is_valid = len(issues) == 0
            confidence = "high" if len(issues) == 0 and len(warnings) == 0 else "medium" if len(issues) == 0 else "low"
            
            return CreativeValidation(
                is_valid=is_valid,
                confidence=confidence,
                issues=issues,
                warnings=warnings,
                recommendations=recommendations,
                format_compliance=self._check_format_compliance(proposed_creative)
            )
            
        except Exception as e:
            logger.error(f"Error validating creative logic: {e}")
            return CreativeValidation(
                is_valid=False,
                confidence="low",
                issues=[f"Validation error: {str(e)}"],
                warnings=[],
                recommendations=[],
                format_compliance="unknown"
            )
    
    async def _validate_campaign_structure_logic(
        self, 
        current_structure: Dict[str, Any], 
        proposed_structure: Dict[str, Any]
    ) -> CampaignStructureValidation:
        """Validate campaign structure logic"""
        try:
            issues = []
            warnings = []
            recommendations = []
            
            # Check required campaign fields
            if "objective" not in proposed_structure:
                issues.append("Campaign objective is required")
            
            if "name" not in proposed_structure:
                issues.append("Campaign name is required")
            
            # Validate objective-specific requirements
            if "objective" in proposed_structure:
                objective = proposed_structure["objective"]
                if objective in ["CONVERSIONS", "LEAD_GENERATION"] and "special_ad_categories" not in proposed_structure:
                    warnings.append("Special ad categories may be required for this objective")
            
            # Check naming conventions
            if "name" in proposed_structure:
                name = proposed_structure["name"]
                if len(name) > 100:
                    warnings.append("Campaign name is very long, consider shortening")
                if not name.strip():
                    issues.append("Campaign name cannot be empty")
            
            # Determine overall validation status
            is_valid = len(issues) == 0
            confidence = "high" if len(issues) == 0 and len(warnings) == 0 else "medium" if len(issues) == 0 else "low"
            
            return CampaignStructureValidation(
                is_valid=is_valid,
                confidence=confidence,
                issues=issues,
                warnings=warnings,
                recommendations=recommendations,
                structure_score=self._calculate_structure_score(proposed_structure)
            )
            
        except Exception as e:
            logger.error(f"Error validating campaign structure logic: {e}")
            return CampaignStructureValidation(
                is_valid=False,
                confidence="low",
                issues=[f"Validation error: {str(e)}"],
                warnings=[],
                recommendations=[],
                structure_score=0
            )
    
    async def _calculate_budget_impact(
        self, 
        current_performance: Dict[str, Any], 
        new_budget: float, 
        budget_type: str
    ) -> ImpactAnalysis:
        """Calculate projected impact of budget change"""
        try:
            current_spend = float(current_performance.get("spend", 0))
            current_impressions = int(current_performance.get("impressions", 0))
            current_clicks = int(current_performance.get("clicks", 0))
            current_conversions = int(current_performance.get("conversions", 0))
            
            # Calculate current efficiency metrics
            current_cpm = (current_spend / current_impressions * 1000) if current_impressions > 0 else 0
            current_cpc = (current_spend / current_clicks) if current_clicks > 0 else 0
            current_conversion_rate = (current_conversions / current_clicks * 100) if current_clicks > 0 else 0
            
            # Estimate impact based on budget change
            if budget_type == "daily":
                current_daily_budget = float(current_performance.get("daily_budget", 0))
                if current_daily_budget > 0:
                    budget_multiplier = new_budget / current_daily_budget
                else:
                    budget_multiplier = 1.0
            else:  # lifetime
                current_lifetime_budget = float(current_performance.get("lifetime_budget", 0))
                if current_lifetime_budget > 0:
                    budget_multiplier = new_budget / current_lifetime_budget
                else:
                    budget_multiplier = 1.0
            
            # Project new metrics (simplified linear projection)
            projected_spend = current_spend * budget_multiplier
            projected_impressions = current_impressions * budget_multiplier
            projected_clicks = current_clicks * budget_multiplier
            projected_conversions = current_conversions * budget_multiplier
            
            # Calculate projected efficiency metrics
            projected_cpm = (projected_spend / projected_impressions * 1000) if projected_impressions > 0 else 0
            projected_cpc = (projected_spend / projected_clicks) if projected_clicks > 0 else 0
            projected_conversion_rate = (projected_conversions / projected_clicks * 100) if projected_clicks > 0 else 0
            
            return ImpactAnalysis(
                metric_changes={
                    "spend": {"current": current_spend, "projected": projected_spend, "change_percent": (projected_spend - current_spend) / current_spend * 100 if current_spend > 0 else 0},
                    "impressions": {"current": current_impressions, "projected": projected_impressions, "change_percent": (projected_impressions - current_impressions) / current_impressions * 100 if current_impressions > 0 else 0},
                    "clicks": {"current": current_clicks, "projected": projected_clicks, "change_percent": (projected_clicks - current_clicks) / current_clicks * 100 if current_clicks > 0 else 0},
                    "conversions": {"current": current_conversions, "projected": projected_conversions, "change_percent": (projected_conversions - current_conversions) / current_conversions * 100 if current_conversions > 0 else 0},
                    "cpm": {"current": current_cpm, "projected": projected_cpm, "change_percent": (projected_cpm - current_cpm) / current_cpm * 100 if current_cpm > 0 else 0},
                    "cpc": {"current": current_cpc, "projected": projected_cpc, "change_percent": (projected_cpc - current_cpc) / current_cpc * 100 if current_cpc > 0 else 0},
                    "conversion_rate": {"current": current_conversion_rate, "projected": projected_conversion_rate, "change_percent": (projected_conversion_rate - current_conversion_rate) / current_conversion_rate * 100 if current_conversion_rate > 0 else 0}
                },
                confidence="medium",
                assumptions=["Linear scaling assumption", "Current performance patterns will continue"],
                risks=["Performance may not scale linearly", "Market conditions may change"]
            )
            
        except Exception as e:
            logger.error(f"Error calculating budget impact: {e}")
            return ImpactAnalysis(
                metric_changes={},
                confidence="low",
                assumptions=[],
                risks=[f"Calculation error: {str(e)}"]
            )
    
    async def _calculate_bid_impact(
        self, 
        current_performance: Dict[str, Any], 
        new_bid: float, 
        bid_type: str
    ) -> ImpactAnalysis:
        """Calculate projected impact of bid change"""
        try:
            current_spend = float(current_performance.get("spend", 0))
            current_impressions = int(current_performance.get("impressions", 0))
            current_clicks = int(current_performance.get("clicks", 0))
            current_conversions = int(current_performance.get("conversions", 0))
            current_cpm = float(current_performance.get("cpm", 0))
            current_cpc = float(current_performance.get("cpc", 0))
            
            # Get current bid (simplified - in reality would need to fetch from adset)
            current_bid = current_cpc  # Use CPC as proxy for bid
            
            # Calculate bid change impact
            if current_bid > 0:
                bid_multiplier = new_bid / current_bid
            else:
                bid_multiplier = 1.0
            
            # Project impact based on bid change
            # Higher bids typically increase impressions but may increase costs
            impression_multiplier = bid_multiplier ** 0.5  # Diminishing returns
            cost_multiplier = bid_multiplier ** 0.8  # Costs increase but not linearly
            
            projected_impressions = current_impressions * impression_multiplier
            projected_spend = current_spend * cost_multiplier
            projected_clicks = current_clicks * impression_multiplier  # Assume CTR stays similar
            projected_conversions = current_conversions * impression_multiplier  # Assume conversion rate stays similar
            
            # Calculate projected efficiency metrics
            projected_cpm = (projected_spend / projected_impressions * 1000) if projected_impressions > 0 else 0
            projected_cpc = (projected_spend / projected_clicks) if projected_clicks > 0 else 0
            projected_conversion_rate = (projected_conversions / projected_clicks * 100) if projected_clicks > 0 else 0
            
            return ImpactAnalysis(
                metric_changes={
                    "spend": {"current": current_spend, "projected": projected_spend, "change_percent": (projected_spend - current_spend) / current_spend * 100 if current_spend > 0 else 0},
                    "impressions": {"current": current_impressions, "projected": projected_impressions, "change_percent": (projected_impressions - current_impressions) / current_impressions * 100 if current_impressions > 0 else 0},
                    "clicks": {"current": current_clicks, "projected": projected_clicks, "change_percent": (projected_clicks - current_clicks) / current_clicks * 100 if current_clicks > 0 else 0},
                    "conversions": {"current": current_conversions, "projected": projected_conversions, "change_percent": (projected_conversions - current_conversions) / current_conversions * 100 if current_conversions > 0 else 0},
                    "cpm": {"current": current_cpm, "projected": projected_cpm, "change_percent": (projected_cpm - current_cpm) / current_cpm * 100 if current_cpm > 0 else 0},
                    "cpc": {"current": current_cpc, "projected": projected_cpc, "change_percent": (projected_cpc - current_cpc) / current_cpc * 100 if current_cpc > 0 else 0},
                    "conversion_rate": {"current": projected_conversion_rate, "projected": projected_conversion_rate, "change_percent": 0}
                },
                confidence="medium",
                assumptions=["Bid changes affect auction competitiveness", "Quality score remains constant"],
                risks=["Auction dynamics may be unpredictable", "Competition may respond to bid changes"]
            )
            
        except Exception as e:
            logger.error(f"Error calculating bid impact: {e}")
            return ImpactAnalysis(
                metric_changes={},
                confidence="low",
                assumptions=[],
                risks=[f"Calculation error: {str(e)}"]
            )
    
    def _estimate_budget_impact(
        self, 
        current_budget: Dict[str, Any], 
        new_budget: float, 
        budget_type: str
    ) -> str:
        """Estimate budget change impact"""
        try:
            if budget_type == "daily":
                current = float(current_budget.get("daily_budget", 0))
            else:
                current = float(current_budget.get("lifetime_budget", 0))
            
            if current > 0:
                change_percent = (new_budget - current) / current * 100
                if abs(change_percent) < 10:
                    return "minimal"
                elif abs(change_percent) < 50:
                    return "moderate"
                else:
                    return "significant"
            else:
                return "new_budget"
                
        except Exception:
            return "unknown"
    
    def _estimate_audience_size(self, targeting: Dict[str, Any]) -> int:
        """Estimate audience size based on targeting criteria"""
        try:
            # Simplified audience size estimation
            base_size = 1000000  # Base audience size
            
            # Adjust based on age range
            if "age_min" in targeting and "age_max" in targeting:
                age_range = targeting["age_max"] - targeting["age_min"]
                age_factor = age_range / 65  # Normalize to full age range
                base_size *= age_factor
            
            # Adjust based on geo targeting
            if "geo_locations" in targeting:
                geo_locations = targeting["geo_locations"]
                if "countries" in geo_locations:
                    country_count = len(geo_locations["countries"])
                    geo_factor = min(country_count * 0.1, 1.0)  # Cap at 1.0
                    base_size *= geo_factor
            
            return int(base_size)
            
        except Exception:
            return 1000000  # Default estimate
    
    def _validate_creative_format(self, story_spec: Dict[str, Any]) -> List[str]:
        """Validate creative format requirements"""
        issues = []
        
        # Check for required fields
        if "page_id" not in story_spec:
            issues.append("Page ID is required")
        
        # Check link data if present
        if "link_data" in story_spec:
            link_data = story_spec["link_data"]
            if "link" not in link_data:
                issues.append("Link URL is required for link ads")
        
        return issues
    
    def _check_format_compliance(self, creative_config: Dict[str, Any]) -> str:
        """Check creative format compliance"""
        try:
            if "object_story_spec" in creative_config:
                story_spec = creative_config["object_story_spec"]
                if "page_id" in story_spec and "link_data" in story_spec:
                    return "compliant"
                elif "page_id" in story_spec:
                    return "partially_compliant"
                else:
                    return "non_compliant"
            else:
                return "unknown"
                
        except Exception:
            return "unknown"
    
    def _calculate_structure_score(self, campaign_config: Dict[str, Any]) -> int:
        """Calculate campaign structure quality score"""
        try:
            score = 0
            
            # Check required fields
            if "name" in campaign_config and campaign_config["name"].strip():
                score += 20
            if "objective" in campaign_config:
                score += 20
            if "status" in campaign_config:
                score += 10
            
            # Check optional but recommended fields
            if "special_ad_categories" in campaign_config:
                score += 10
            if "buying_type" in campaign_config:
                score += 10
            
            # Check naming quality
            if "name" in campaign_config:
                name = campaign_config["name"]
                if len(name) > 10 and len(name) < 50:
                    score += 10
                if any(keyword in name.lower() for keyword in ["test", "campaign", "ad"]):
                    score += 10
            
            return min(score, 100)
            
        except Exception:
            return 0


# Global validation engine instance
_validation_engine: Optional[ValidationEngine] = None


def get_validation_engine() -> ValidationEngine:
    """Get the global ValidationEngine instance"""
    global _validation_engine
    if _validation_engine is None:
        from .meta_client import get_client
        _validation_engine = ValidationEngine(get_client())
    return _validation_engine
