from datetime import datetime
from typing import Literal
from fastapi import HTTPException
from pydantic import BaseModel, Field
from sqlalchemy import INTEGER, TEXT, VARCHAR, DateTime, Enum, func
from sqlalchemy.orm import Mapped, Session, mapped_column, relationship

from app.models.main import Base
from app.models.main.category import CategoryEnum


class SimulationBase(BaseModel):
    
    simulation_id : int | None = Field(default=None)
    simulation_name: str | None = Field(default=None)
    description : str | None = Field(default=None)
    status: Literal["Active", "Pending", "Completed"] = "Pending"
    start_date: datetime | None = Field(default=None)
    end_date: datetime | None = Field(default=None)
    institution: str | None = Field(default=None)
    location: str | None = Field(default=None)
    simulation_code: str | None = Field(default=None)
    members : int | None = Field(default=None)

class TblSimulation(Base):
    __tablename__ = "tbl_simulation"

    simulation_id: Mapped[int] = mapped_column("simulation_id", INTEGER, primary_key=True, autoincrement=True)
    simulation_name: Mapped[str] = mapped_column("simulation_name", VARCHAR(255), nullable=True)
    description: Mapped[str] = mapped_column("description", TEXT, nullable=True)
    status: Mapped[str] = mapped_column(Enum("Active", "Pending", "Completed", name="simulation_status"), nullable=True, server_default="Pending")
    start_date: Mapped[datetime] = mapped_column("start_date", DateTime(timezone=True), server_default=func.now(), nullable=True)
    end_date: Mapped[datetime] = mapped_column("end_date", DateTime, nullable=True)
    institution: Mapped[str] = mapped_column("institution", VARCHAR(255), nullable=True)
    location: Mapped[str] = mapped_column("location", VARCHAR(255), nullable=True)
    simulation_code: Mapped[str] = mapped_column("simulation_code", VARCHAR(100), nullable=True, unique=True)
    members : Mapped[int] = mapped_column("members", INTEGER, nullable=True, server_default=None)

    groups = relationship("TblGroup", back_populates="simulation")
    payments = relationship("TblPayment", back_populates="simulation")
    user_sim_simulation = relationship("TblUserSimulation", back_populates="simulation")
    category_simulation = relationship("TblCategorySimulation", back_populates="simulation")

    @classmethod
    def create(cls, data: SimulationBase, db: Session) -> "TblSimulation":
        data_dict = data.model_dump()
        new_data = cls(**data_dict)
        db.add(new_data)
        db.flush()
        return new_data
    
    @classmethod
    def get_by_id(cls, simulation_id: int, db: Session) -> "TblSimulation":
        get_data = db.query(cls).filter(cls.simulation_id == simulation_id).first()
        if not get_data:
            raise HTTPException(status_code=404, detail="Simulation not found")
        return get_data
    
    @classmethod
    def update(cls, simulation_id: int, data: SimulationBase, db: Session) -> "TblSimulation":
        get_data = db.query(cls).filter(cls.simulation_id == simulation_id).first()
        if not get_data:
            raise HTTPException(status_code=404, detail="User not found")
        data_dict = data.model_dump()
        for key, value in data_dict.items():
            setattr(get_data, key, value)
        db.add(get_data)
        db.flush()
        return get_data
    
    @classmethod
    def delete(cls, simulation_id: int, db: Session) -> bool:
        obj = db.query(cls).filter(cls.simulation_id == simulation_id).first()
        if not obj:
            return False
        db.delete(obj)
        db.commit()
        return True
