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

from sqlalchemy import DateTime, Enum as SAEnum, Float, ForeignKey, Integer, JSON, String, Text
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.database import Base


class IrrigationMethod(enum.Enum):
    drip = "drip"
    sprinkler = "sprinkler"
    flood = "flood"
    rainfed = "rainfed"


class Season(enum.Enum):
    spring = "spring"
    summer = "summer"
    autumn = "autumn"
    winter = "winter"


class Scenario(Base):
    __tablename__ = "scenarios"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    graft_combination_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True), ForeignKey("graft_combinations.id"), nullable=True
    )
    plant_id: Mapped[Optional[uuid.UUID]] = mapped_column(
        UUID(as_uuid=True), ForeignKey("plants.id"), nullable=True
    )
    soil_profile_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("soil_profiles.id"), nullable=False
    )
    applied_nitrogen: Mapped[float] = mapped_column(Float, nullable=False)
    applied_phosphorus: Mapped[float] = mapped_column(Float, nullable=False)
    applied_potassium: Mapped[float] = mapped_column(Float, nullable=False)
    irrigation_method: Mapped[IrrigationMethod] = mapped_column(
        SAEnum(IrrigationMethod, name="irrigationmethod"), nullable=False
    )
    irrigation_frequency_days: Mapped[int] = mapped_column(Integer, nullable=False)
    season: Mapped[Season] = mapped_column(
        SAEnum(Season, name="season"), nullable=False
    )
    duration_days: Mapped[int] = mapped_column(Integer, nullable=False)
    client_ip: Mapped[Optional[str]] = mapped_column(String(45), nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True),
        default=lambda: datetime.now(timezone.utc),
        onupdate=lambda: datetime.now(timezone.utc),
    )

    graft_combination: Mapped[Optional["GraftCombination"]] = relationship(  # type: ignore[name-defined]
        "GraftCombination", back_populates="scenarios"
    )
    plant: Mapped[Optional["Plant"]] = relationship(  # type: ignore[name-defined]
        "Plant", foreign_keys=[plant_id], back_populates="ungrafted_scenarios"
    )
    soil_profile: Mapped["SoilProfile"] = relationship(  # type: ignore[name-defined]
        "SoilProfile", back_populates="scenarios"
    )
    results: Mapped[Optional["ScenarioResult"]] = relationship(
        "ScenarioResult", back_populates="scenario", uselist=False
    )


class ScenarioResult(Base):
    __tablename__ = "scenario_results"

    id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), primary_key=True, default=uuid.uuid4
    )
    scenario_id: Mapped[uuid.UUID] = mapped_column(
        UUID(as_uuid=True), ForeignKey("scenarios.id"), nullable=False
    )
    predicted_yield: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    survival_probability: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    risk_factors: Mapped[List[Any]] = mapped_column(JSON, default=list)
    recommended_adjustments: Mapped[Dict[str, Any]] = mapped_column(JSON, default=dict)
    growth_timeline: Mapped[List[Any]] = mapped_column(JSON, default=list)
    confidence_score: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    ai_analysis: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)
    )

    scenario: Mapped["Scenario"] = relationship("Scenario", back_populates="results")
