"""
Strategic Monitoring Engine

Real-time spend monitoring, anomaly detection, and financial controls
for enterprise advertisers spending $10M+/year.
"""

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

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

logger = get_logger(__name__)


class StrategicMonitoringEngine(BaseEngine):
    """Strategic monitoring for enterprise spend management.
    
    Capabilities:
    - Real-time spend tracking
    - Anomaly detection
    - Budget guardrails
    - Financial controls
    """
    
    async def initialize(self) -> None:
        """Initialize strategic monitoring engine."""
        logger.info("strategic_monitoring_engine_initialized")
        self._initialized = True
    
    async def shutdown(self) -> None:
        """Shutdown strategic monitoring engine."""
        logger.info("strategic_monitoring_engine_shutdown")
        self._shutdown = True
    
    async def get_real_time_spend_feed(
        self,
        ad_account_id: str,
        granularity: str = "hourly",
        currency: str = "USD",
        include_forecast: bool = True
    ) -> Dict[str, Any]:
        """Get real-time spend feed for CFO/finance teams.
        
        Provides:
        - Hourly/daily spend tracking
        - Multi-currency conversion
        - Budget utilization
        - Spend forecasting
        
        Args:
            ad_account_id: Meta ad account ID
            granularity: 'hourly' or 'daily'
            currency: Target currency for reporting
            include_forecast: Include spend forecast
        
        Returns:
            Real-time spend data formatted for finance systems
        """
        await self._ensure_initialized()
        
        logger.info("getting_real_time_spend_feed", ad_account_id=ad_account_id)
        
        try:
            # Get today's spend
            today = datetime.now().strftime("%Y-%m-%d")
            time_range = {
                "since": today,
                "until": today
            }
            
            # Get hourly spend data
            insights = await self.client.get_insights(
                object_id=ad_account_id,
                level="account",
                fields=["spend", "impressions", "clicks", "actions"],
                time_increment="1" if granularity == "hourly" else "all_days",
                time_range=time_range
            )
            
            data = insights.get("data", [])
            
            # Get account info for budget limits
            account_info = await self.client.get_ad_account(
                ad_account_id=ad_account_id,
                fields=["account_id", "name", "currency", "timezone_name", "spend_cap"]
            )
            
            # Calculate current spend
            current_spend = sum(float(d.get("spend", 0)) for d in data)
            spend_cap = float(account_info.get("spend_cap", 0))
            
            feed = {
                "ad_account_id": ad_account_id,
                "account_name": account_info.get("name", "Unknown"),
                "timestamp": datetime.now().isoformat(),
                "currency": account_info.get("currency", "USD"),
                "timezone": account_info.get("timezone_name", "UTC"),
                "current_spend": round(current_spend, 2),
                "spend_cap": spend_cap if spend_cap > 0 else None,
                "utilization_percentage": round((current_spend / spend_cap * 100), 2) if spend_cap > 0 else None,
                "hourly_breakdown": []
            }
            
            # Add hourly breakdown
            for insight in data:
                feed["hourly_breakdown"].append({
                    "timestamp": insight.get("date_start", ""),
                    "spend": round(float(insight.get("spend", 0)), 2),
                    "impressions": int(insight.get("impressions", 0)),
                    "clicks": int(insight.get("clicks", 0))
                })
            
            # Forecast end-of-day spend
            if include_forecast and len(feed["hourly_breakdown"]) > 0:
                current_hour = datetime.now().hour
                if current_hour > 0:
                    avg_hourly_spend = current_spend / current_hour
                    forecast_eod = avg_hourly_spend * 24
                    
                    feed["forecast"] = {
                        "end_of_day_spend": round(forecast_eod, 2),
                        "remaining_hours": 24 - current_hour,
                        "projected_hourly_spend": round(avg_hourly_spend, 2),
                        "on_pace_for_budget": spend_cap > 0 and forecast_eod <= spend_cap
                    }
            
            # Format for ERP integration
            feed["erp_format"] = {
                "journal_entry_ready": True,
                "debit_account": "Marketing Expense",
                "credit_account": "Accounts Payable - Meta",
                "amount": current_spend,
                "currency": account_info.get("currency", "USD"),
                "posting_date": today,
                "reference": f"Meta-{ad_account_id}-{today}"
            }
            
            logger.info("real_time_spend_feed_generated", current_spend=current_spend)
            return feed
            
        except Exception as e:
            logger.error("real_time_spend_feed_failed: %s", str(e))
            raise EngineError(f"Real-time spend feed failed: {str(e)}", engine="StrategicMonitoring")
    
    async def detect_spend_anomalies(
        self,
        ad_account_id: str,
        lookback_days: int = 30,
        anomaly_threshold: float = 2.5,
        alert_on_spike: bool = True
    ) -> Dict[str, Any]:
        """Detect unusual spend spikes for security/fraud prevention.
        
        Detects:
        - Sudden spend increases (hacked accounts)
        - Budget overruns
        - Unusual patterns
        
        Args:
            ad_account_id: Meta ad account ID
            lookback_days: Days of history to analyze
            anomaly_threshold: Standard deviations for anomaly (default: 2.5)
            alert_on_spike: Alert on upward spikes
        
        Returns:
            Anomaly detection results with alerts
        """
        await self._ensure_initialized()
        
        logger.info("detecting_spend_anomalies", ad_account_id=ad_account_id)
        
        try:
            # Get historical spend data
            time_range = {
                "since": (datetime.now() - timedelta(days=lookback_days)).strftime("%Y-%m-%d"),
                "until": datetime.now().strftime("%Y-%m-%d")
            }
            
            insights = await self.client.get_insights(
                object_id=ad_account_id,
                level="account",
                fields=["spend"],
                time_increment=1,
                time_range=time_range
            )
            
            data = insights.get("data", [])
            if len(data) < 7:
                return {
                    "anomalies_detected": False,
                    "message": "Insufficient data for anomaly detection (need 7+ days)"
                }
            
            # Calculate statistics
            spend_values = [float(d.get("spend", 0)) for d in data]
            mean_spend = sum(spend_values) / len(spend_values)
            variance = sum((x - mean_spend) ** 2 for x in spend_values) / len(spend_values)
            std_dev = variance ** 0.5
            
            # Detect anomalies
            anomalies = []
            for i, insight in enumerate(data):
                date = insight.get("date_start", "")
                spend = float(insight.get("spend", 0))
                z_score = (spend - mean_spend) / std_dev if std_dev > 0 else 0
                
                if abs(z_score) > anomaly_threshold:
                    severity = "critical" if abs(z_score) > 3 else "high" if abs(z_score) > 2.5 else "medium"
                    
                    anomalies.append({
                        "date": date,
                        "spend": round(spend, 2),
                        "mean_spend": round(mean_spend, 2),
                        "std_dev": round(std_dev, 2),
                        "z_score": round(z_score, 2),
                        "deviation_percentage": round(((spend - mean_spend) / mean_spend * 100), 2),
                        "severity": severity,
                        "type": "spike" if spend > mean_spend else "drop"
                    })
            
            # Generate analysis
            analysis = {
                "ad_account_id": ad_account_id,
                "analysis_period": time_range,
                "anomalies_detected": len(anomalies) > 0,
                "anomaly_count": len(anomalies),
                "anomalies": sorted(anomalies, key=lambda x: abs(x["z_score"]), reverse=True),
                "statistics": {
                    "mean_daily_spend": round(mean_spend, 2),
                    "std_dev": round(std_dev, 2),
                    "min_spend": round(min(spend_values), 2),
                    "max_spend": round(max(spend_values), 2),
                    "total_spend": round(sum(spend_values), 2)
                },
                "alerts": []
            }
            
            # Generate alerts for critical anomalies
            critical_anomalies = [a for a in anomalies if a["severity"] == "critical"]
            if critical_anomalies:
                analysis["alerts"].append({
                    "priority": "critical",
                    "message": f"{len(critical_anomalies)} critical spend anomalies detected",
                    "action": "Immediately verify account security and review campaign changes",
                    "potential_impact": "Possible account compromise or configuration error"
                })
            
            # Check for recent spikes
            recent_anomalies = [a for a in anomalies if a["type"] == "spike"][-3:]
            if len(recent_anomalies) >= 2 and alert_on_spike:
                analysis["alerts"].append({
                    "priority": "high",
                    "message": "Multiple recent spend spikes detected",
                    "action": "Review campaign settings and budget allocations",
                    "dates": [a["date"] for a in recent_anomalies]
                })
            
            logger.info("spend_anomaly_detection_complete", anomalies_found=len(anomalies))
            return analysis
            
        except Exception as e:
            logger.error("spend_anomaly_detection_failed: %s", str(e))
            raise EngineError(f"Spend anomaly detection failed: {str(e)}", engine="StrategicMonitoring")
    
    async def enforce_budget_guardrails(
        self,
        ad_account_id: str,
        daily_limit: Optional[float] = None,
        monthly_limit: Optional[float] = None,
        auto_pause: bool = False,
        alert_threshold: float = 0.8
    ) -> Dict[str, Any]:
        """Enforce budget guardrails and spending limits.
        
        Provides:
        - Hard spend caps
        - Auto-pause on threshold
        - Alert notifications
        - Budget compliance tracking
        
        Args:
            ad_account_id: Meta ad account ID
            daily_limit: Maximum daily spend
            monthly_limit: Maximum monthly spend
            auto_pause: Auto-pause campaigns on limit
            alert_threshold: Alert when % of limit reached (0.8 = 80%)
        
        Returns:
            Guardrail status and enforcement actions
        """
        await self._ensure_initialized()
        
        logger.info("enforcing_budget_guardrails", ad_account_id=ad_account_id)
        
        try:
            # Get current spend
            today = datetime.now().strftime("%Y-%m-%d")
            month_start = datetime.now().replace(day=1).strftime("%Y-%m-%d")
            
            # Get today's spend
            daily_insights = await self.client.get_insights(
                object_id=ad_account_id,
                level="account",
                fields=["spend"],
                time_range={"since": today, "until": today}
            )
            
            # Get month-to-date spend
            monthly_insights = await self.client.get_insights(
                object_id=ad_account_id,
                level="account",
                fields=["spend"],
                time_range={"since": month_start, "until": today}
            )
            
            daily_spend = sum(float(d.get("spend", 0)) for d in daily_insights.get("data", []))
            monthly_spend = sum(float(d.get("spend", 0)) for d in monthly_insights.get("data", []))
            
            guardrail_status = {
                "ad_account_id": ad_account_id,
                "timestamp": datetime.now().isoformat(),
                "daily_spend": round(daily_spend, 2),
                "monthly_spend": round(monthly_spend, 2),
                "guardrails": {
                    "daily_limit": daily_limit,
                    "monthly_limit": monthly_limit,
                    "auto_pause_enabled": auto_pause,
                    "alert_threshold": alert_threshold
                },
                "compliance": {
                    "daily_compliant": True,
                    "monthly_compliant": True
                },
                "alerts": [],
                "actions_taken": []
            }
            
            # Check daily limit
            if daily_limit:
                daily_utilization = daily_spend / daily_limit
                guardrail_status["compliance"]["daily_compliant"] = daily_spend <= daily_limit
                guardrail_status["compliance"]["daily_utilization"] = round(daily_utilization, 2)
                
                if daily_spend > daily_limit:
                    guardrail_status["alerts"].append({
                        "severity": "critical",
                        "type": "daily_limit_exceeded",
                        "message": f"Daily spend ${daily_spend:.2f} exceeds limit ${daily_limit:.2f}",
                        "overage": round(daily_spend - daily_limit, 2)
                    })
                    
                    if auto_pause:
                        # In production, this would pause all campaigns
                        guardrail_status["actions_taken"].append({
                            "action": "auto_pause_campaigns",
                            "reason": "Daily limit exceeded",
                            "timestamp": datetime.now().isoformat()
                        })
                
                elif daily_utilization >= alert_threshold:
                    guardrail_status["alerts"].append({
                        "severity": "warning",
                        "type": "daily_threshold_approaching",
                        "message": f"Daily spend at {daily_utilization*100:.0f}% of limit",
                        "remaining": round(daily_limit - daily_spend, 2)
                    })
            
            # Check monthly limit
            if monthly_limit:
                monthly_utilization = monthly_spend / monthly_limit
                guardrail_status["compliance"]["monthly_compliant"] = monthly_spend <= monthly_limit
                guardrail_status["compliance"]["monthly_utilization"] = round(monthly_utilization, 2)
                
                if monthly_spend > monthly_limit:
                    guardrail_status["alerts"].append({
                        "severity": "critical",
                        "type": "monthly_limit_exceeded",
                        "message": f"Monthly spend ${monthly_spend:.2f} exceeds limit ${monthly_limit:.2f}",
                        "overage": round(monthly_spend - monthly_limit, 2)
                    })
                    
                    if auto_pause:
                        guardrail_status["actions_taken"].append({
                            "action": "auto_pause_campaigns",
                            "reason": "Monthly limit exceeded",
                            "timestamp": datetime.now().isoformat()
                        })
                
                elif monthly_utilization >= alert_threshold:
                    guardrail_status["alerts"].append({
                        "severity": "warning",
                        "type": "monthly_threshold_approaching",
                        "message": f"Monthly spend at {monthly_utilization*100:.0f}% of limit",
                        "remaining": round(monthly_limit - monthly_spend, 2)
                    })
            
            logger.info(
                "budget_guardrails_enforced",
                alerts=len(guardrail_status["alerts"]),
                actions=len(guardrail_status["actions_taken"])
            )
            
            return guardrail_status
            
        except Exception as e:
            logger.error("budget_guardrail_enforcement_failed: %s", str(e))
            raise EngineError(f"Budget guardrail enforcement failed: {str(e)}", engine="StrategicMonitoring")

