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

from pydantic import BaseModel, ConfigDict, model_validator

from app.models.scenario import IrrigationMethod, Season
from app.schemas.graft_combination import GraftCombinationResponse
from app.schemas.plant import PlantResponse
from app.schemas.soil_profile import SoilProfileResponse


class ScenarioCreate(BaseModel):
    name: str
    graft_combination_id: Optional[uuid.UUID] = None
    plant_id: Optional[uuid.UUID] = None
    soil_profile_id: uuid.UUID
    applied_nitrogen: float
    applied_phosphorus: float
    applied_potassium: float
    irrigation_method: IrrigationMethod
    irrigation_frequency_days: int
    season: Season
    duration_days: int

    @model_validator(mode="after")
    def check_plant_or_graft(self) -> "ScenarioCreate":
        if self.graft_combination_id is None and self.plant_id is None:
            raise ValueError("Either graft_combination_id or plant_id must be provided")
        if self.graft_combination_id is not None and self.plant_id is not None:
            raise ValueError("Provide either graft_combination_id or plant_id, not both")
        return self


class AnalyzeRequest(BaseModel):
    """Same as ScenarioCreate but name is optional — used for ephemeral analysis."""
    name: Optional[str] = None
    graft_combination_id: Optional[uuid.UUID] = None
    plant_id: Optional[uuid.UUID] = None
    soil_profile_id: uuid.UUID
    applied_nitrogen: float
    applied_phosphorus: float
    applied_potassium: float
    irrigation_method: IrrigationMethod
    irrigation_frequency_days: int
    season: Season
    duration_days: int

    @model_validator(mode="after")
    def check_plant_or_graft(self) -> "AnalyzeRequest":
        if self.graft_combination_id is None and self.plant_id is None:
            raise ValueError("Either graft_combination_id or plant_id must be provided")
        if self.graft_combination_id is not None and self.plant_id is not None:
            raise ValueError("Provide either graft_combination_id or plant_id, not both")
        return self


class ScenarioResultResponse(BaseModel):
    id: uuid.UUID
    scenario_id: uuid.UUID
    predicted_yield: Optional[float]
    survival_probability: Optional[float]
    risk_factors: List[Any]
    recommended_adjustments: Dict[str, Any]
    growth_timeline: List[Any]
    confidence_score: Optional[float]
    ai_analysis: Optional[str]
    created_at: datetime

    model_config = ConfigDict(from_attributes=True)


class ScenarioResponse(BaseModel):
    id: uuid.UUID
    name: str
    graft_combination_id: Optional[uuid.UUID]
    plant_id: Optional[uuid.UUID]
    soil_profile_id: uuid.UUID
    applied_nitrogen: float
    applied_phosphorus: float
    applied_potassium: float
    irrigation_method: IrrigationMethod
    irrigation_frequency_days: int
    season: Season
    duration_days: int
    created_at: datetime
    updated_at: datetime
    soil_profile: SoilProfileResponse
    graft_combination: Optional[GraftCombinationResponse] = None
    plant: Optional[PlantResponse] = None
    results: Optional[ScenarioResultResponse] = None

    model_config = ConfigDict(from_attributes=True)


class ScenarioSummary(BaseModel):
    """Lightweight version for list views — no full nested objects."""
    id: uuid.UUID
    name: str
    season: Season
    duration_days: int
    created_at: datetime
    predicted_yield: Optional[float] = None
    survival_probability: Optional[float] = None
    confidence_score: Optional[float] = None

    model_config = ConfigDict(from_attributes=True)
