# ================================================================
# services/forecasting/app/schemas/forecasts.py
# ================================================================
"""
Forecast schemas for request/response validation
"""

from pydantic import BaseModel, Field, validator
from datetime import datetime, date
from typing import Optional, List, Dict, Any
from enum import Enum
from uuid import UUID

class BusinessType(str, Enum):
    INDIVIDUAL = "individual"
    CENTRAL_WORKSHOP = "central_workshop"


class ForecastRequest(BaseModel):
    """Request schema for generating forecasts"""
    inventory_product_id: str = Field(..., description="Inventory product UUID reference")
    # product_name: str = Field(..., description="Product name")  # DEPRECATED - use inventory_product_id
    forecast_date: date = Field(..., description="Starting date for forecast")
    forecast_days: int = Field(1, ge=1, le=30, description="Number of days to forecast")
    location: str = Field(..., description="Location identifier")

    # Optional parameters - internally handled
    confidence_level: float = Field(0.8, ge=0.5, le=0.95, description="Confidence level")

    @validator('inventory_product_id')
    def validate_inventory_product_id(cls, v):
        """Validate that inventory_product_id is a valid UUID"""
        try:
            UUID(v)
        except (ValueError, AttributeError):
            raise ValueError(f"inventory_product_id must be a valid UUID, got: {v}")
        return v

    @validator('forecast_date')
    def validate_forecast_date(cls, v):
        if v < date.today():
            raise ValueError("Forecast date cannot be in the past")
        return v

class BatchForecastRequest(BaseModel):
    """Request schema for batch forecasting"""
    tenant_id: Optional[str] = None  # Optional, can be from path parameter
    batch_name: str = Field(..., description="Batch name for tracking")
    inventory_product_ids: List[str] = Field(..., description="List of inventory product IDs")
    forecast_days: int = Field(7, ge=1, le=30, description="Number of days to forecast")

    @validator('tenant_id')
    def validate_tenant_id(cls, v):
        """Validate that tenant_id is a valid UUID if provided"""
        if v is not None:
            try:
                UUID(v)
            except (ValueError, AttributeError):
                raise ValueError(f"tenant_id must be a valid UUID, got: {v}")
        return v

    @validator('inventory_product_ids')
    def validate_inventory_product_ids(cls, v):
        """Validate that all inventory_product_ids are valid UUIDs"""
        for product_id in v:
            try:
                UUID(product_id)
            except (ValueError, AttributeError):
                raise ValueError(f"All inventory_product_ids must be valid UUIDs, got invalid: {product_id}")
        return v

class ForecastResponse(BaseModel):
    """Response schema for forecast results"""
    id: str
    tenant_id: str
    inventory_product_id: str  # Reference to inventory service
    # product_name: str  # Can be fetched from inventory service if needed for display
    location: str
    forecast_date: datetime
    
    # Predictions
    predicted_demand: float
    confidence_lower: float
    confidence_upper: float
    confidence_level: float
    
    # Model info
    model_id: str
    model_version: str
    algorithm: str
    
    # Context
    business_type: str
    is_holiday: bool
    is_weekend: bool
    day_of_week: int
    
    # External factors
    weather_temperature: Optional[float]
    weather_precipitation: Optional[float]
    weather_description: Optional[str]
    traffic_volume: Optional[int]
    
    # Metadata
    created_at: datetime
    processing_time_ms: Optional[int]
    features_used: Optional[Dict[str, Any]]

class BatchForecastResponse(BaseModel):
    """Response schema for batch forecast requests"""
    id: str
    tenant_id: str
    batch_name: str
    status: str
    total_products: int
    completed_products: int
    failed_products: int
    
    # Timing
    requested_at: datetime
    completed_at: Optional[datetime]
    processing_time_ms: Optional[int]
    
    # Results
    forecasts: Optional[List[ForecastResponse]]
    error_message: Optional[str]

class MultiDayForecastResponse(BaseModel):
    """Response schema for multi-day forecast results"""
    tenant_id: str = Field(..., description="Tenant ID")
    inventory_product_id: str = Field(..., description="Inventory product ID")
    forecast_start_date: date = Field(..., description="Start date of forecast period")
    forecast_days: int = Field(..., description="Number of forecasted days")
    forecasts: List[ForecastResponse] = Field(..., description="Daily forecasts")
    total_predicted_demand: float = Field(..., description="Total demand across all days")
    average_confidence_level: float = Field(..., description="Average confidence across all days")
    processing_time_ms: int = Field(..., description="Total processing time")


# ================================================================
# SCENARIO SIMULATION SCHEMAS - PROFESSIONAL/ENTERPRISE ONLY
# ================================================================

class ScenarioType(str, Enum):
    """Types of scenarios available for simulation"""
    WEATHER = "weather"  # Weather impact (heatwave, cold snap, rain, etc.)
    COMPETITION = "competition"  # New competitor opening nearby
    EVENT = "event"  # Local event (festival, sports, concert, etc.)
    PRICING = "pricing"  # Price changes
    PROMOTION = "promotion"  # Promotional campaigns
    HOLIDAY = "holiday"  # Holiday periods
    SUPPLY_DISRUPTION = "supply_disruption"  # Supply chain issues
    CUSTOM = "custom"  # Custom user-defined scenario


class WeatherScenario(BaseModel):
    """Weather scenario parameters"""
    temperature_change: Optional[float] = Field(None, ge=-30, le=30, description="Temperature change in °C")
    precipitation_change: Optional[float] = Field(None, ge=0, le=100, description="Precipitation change in mm")
    weather_type: Optional[str] = Field(None, description="Weather type (heatwave, cold_snap, rainy, etc.)")


class CompetitionScenario(BaseModel):
    """Competition scenario parameters"""
    new_competitors: int = Field(1, ge=1, le=10, description="Number of new competitors")
    distance_km: float = Field(0.5, ge=0.1, le=10, description="Distance from location in km")
    estimated_market_share_loss: float = Field(0.1, ge=0, le=0.5, description="Estimated market share loss (0-50%)")


class EventScenario(BaseModel):
    """Event scenario parameters"""
    event_type: str = Field(..., description="Type of event (festival, sports, concert, etc.)")
    expected_attendance: int = Field(..., ge=0, description="Expected attendance")
    distance_km: float = Field(0.5, ge=0, le=50, description="Distance from location in km")
    duration_days: int = Field(1, ge=1, le=30, description="Duration in days")


class PricingScenario(BaseModel):
    """Pricing scenario parameters"""
    price_change_percent: float = Field(..., ge=-50, le=100, description="Price change percentage")
    affected_products: Optional[List[str]] = Field(None, description="List of affected product IDs")


class PromotionScenario(BaseModel):
    """Promotion scenario parameters"""
    discount_percent: float = Field(..., ge=0, le=75, description="Discount percentage")
    promotion_type: str = Field(..., description="Type of promotion (bogo, discount, bundle, etc.)")
    expected_traffic_increase: float = Field(0.2, ge=0, le=2, description="Expected traffic increase (0-200%)")


class ScenarioSimulationRequest(BaseModel):
    """Request schema for scenario simulation - PROFESSIONAL/ENTERPRISE ONLY"""
    scenario_name: str = Field(..., min_length=3, max_length=200, description="Name for this scenario")
    scenario_type: ScenarioType = Field(..., description="Type of scenario to simulate")
    inventory_product_ids: List[str] = Field(..., min_items=1, description="Products to simulate")
    start_date: date = Field(..., description="Simulation start date")
    duration_days: int = Field(7, ge=1, le=30, description="Simulation duration in days")

    # Scenario-specific parameters (one should be provided based on scenario_type)
    weather_params: Optional[WeatherScenario] = None
    competition_params: Optional[CompetitionScenario] = None
    event_params: Optional[EventScenario] = None
    pricing_params: Optional[PricingScenario] = None
    promotion_params: Optional[PromotionScenario] = None

    # Custom scenario parameters
    custom_multipliers: Optional[Dict[str, float]] = Field(
        None,
        description="Custom multipliers for baseline forecast (e.g., {'demand': 1.2, 'traffic': 0.8})"
    )

    # Comparison settings
    include_baseline: bool = Field(True, description="Include baseline forecast for comparison")

    @validator('start_date')
    def validate_start_date(cls, v):
        if v < date.today():
            raise ValueError("Simulation start date cannot be in the past")
        return v


class ScenarioImpact(BaseModel):
    """Impact of scenario on a specific product"""
    inventory_product_id: str
    baseline_demand: float
    simulated_demand: float
    demand_change_percent: float
    confidence_range: tuple[float, float]
    impact_factors: Dict[str, Any]  # Breakdown of what drove the change


class ScenarioSimulationResponse(BaseModel):
    """Response schema for scenario simulation"""
    id: str = Field(..., description="Simulation ID")
    tenant_id: str
    scenario_name: str
    scenario_type: ScenarioType

    # Simulation parameters
    start_date: date
    end_date: date
    duration_days: int

    # Results
    baseline_forecasts: Optional[List[ForecastResponse]] = Field(
        None,
        description="Baseline forecasts (if requested)"
    )
    scenario_forecasts: List[ForecastResponse] = Field(..., description="Forecasts with scenario applied")

    # Impact summary
    total_baseline_demand: float
    total_scenario_demand: float
    overall_impact_percent: float
    product_impacts: List[ScenarioImpact]

    # Insights and recommendations
    insights: List[str] = Field(..., description="AI-generated insights about the scenario")
    recommendations: List[str] = Field(..., description="Actionable recommendations")
    risk_level: str = Field(..., description="Risk level: low, medium, high")

    # Metadata
    created_at: datetime
    processing_time_ms: int

    class Config:
        json_schema_extra = {
            "example": {
                "id": "scenario_123",
                "tenant_id": "tenant_456",
                "scenario_name": "Summer Heatwave Impact",
                "scenario_type": "weather",
                "overall_impact_percent": 15.5,
                "insights": [
                    "Cold beverages expected to increase by 45%",
                    "Bread products may decrease by 8% due to reduced appetite",
                    "Ice cream demand projected to surge by 120%"
                ],
                "recommendations": [
                    "Increase cold beverage inventory by 40%",
                    "Reduce bread production by 10%",
                    "Stock additional ice cream varieties"
                ],
                "risk_level": "medium"
            }
        }


class ScenarioComparisonRequest(BaseModel):
    """Request to compare multiple scenarios"""
    scenario_ids: List[str] = Field(..., min_items=2, max_items=5, description="Scenario IDs to compare")


class ScenarioComparisonResponse(BaseModel):
    """Response comparing multiple scenarios"""
    scenarios: List[ScenarioSimulationResponse]
    comparison_matrix: Dict[str, Dict[str, Any]]
    best_case_scenario_id: str
    worst_case_scenario_id: str
    recommended_action: str


