from datetime import datetime
from typing import Literal, Optional
from fastapi import HTTPException
from pydantic import Field
from sqlalchemy import INTEGER,VARCHAR, DateTime, Enum, ForeignKey, text
from app.models.main import Base
from app.utils.schemas_utils import CustomModel
from sqlalchemy.orm import (Mapped,Session,mapped_column,relationship)

class StudentBase(CustomModel):
    
    student_id: int | None = Field(default=None)
    first_name: str | None = Field(default=None)
    last_name: str | None = Field(default=None)
    student_email: str | None = Field(default=None)
    password: str | None = Field(default=None)
    roll_no :  int | None = Field(default=None)
    group_code:str | None = Field(default=None)
    

class StudentFilter(CustomModel):
    student_id: int | None = Field(default=None) 
    student_email: str | None = Field(default=None)     

class TblStudent(Base):
    __tablename__ = "tbl_student"

    student_id: Mapped[int] = mapped_column("student_id", INTEGER, primary_key=True, autoincrement=True)
    first_name: Mapped[str] = mapped_column("first_name", VARCHAR(255), nullable=True)
    last_name: Mapped[str] = mapped_column("last_name", VARCHAR(255), nullable=True)
    student_email: Mapped[str] = mapped_column("student_email", VARCHAR(255), nullable=True)
    password: Mapped[str] = mapped_column("password", VARCHAR(255), nullable=False)
    roll_no : Mapped[int] = mapped_column("roll_no", INTEGER, nullable=True, server_default=None)
    group_code: Mapped[str] = mapped_column("group_code", VARCHAR(100), ForeignKey("tbl_group.group_code"), nullable=True)
    login_status: Mapped[str] = mapped_column("login_status", Enum("0", "1"), nullable=True, server_default=text("1"))
    otp: Mapped[Optional[str]] = mapped_column(VARCHAR(6), nullable=True, server_default=None)
    otp_expiry: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)

    group = relationship("TblGroup", back_populates="students")

    @classmethod
    def create(cls, data: StudentBase, db: Session) -> "TblStudent":
        data_dict = data.model_dump()
        new_data = cls(**data_dict)
        db.add(new_data)
        db.flush()
        return new_data

    @classmethod
    def get_by_student_email(cls, student_email: int, db: Session) -> "TblStudent":
        get_data = db.query(cls).filter(cls.student_email == student_email).first()
        if not get_data:
            raise HTTPException(status_code=404, detail="User not found") 
        return get_data 
    
    @classmethod
    def get_by_id(cls, student_id: int, db: Session) -> "TblStudent":  
        get_data = db.query(cls).filter(cls.student_id == student_id).first()
        if not get_data:
            raise HTTPException(status_code=404, detail="Student not found") 
        return get_data
    
    @classmethod
    def update(cls,  student_id : int, data: StudentBase, db: Session) -> "TblStudent":
        get_data = db.query(cls).filter(cls. student_id ==  student_id ).first()
        if not get_data:
            raise HTTPException(status_code=404, detail="Store format not found") 
        data_dict = data.model_dump()
        for key, value in data_dict.items():
            if value is not None:
                setattr(get_data, key, value)
        db.commit() 
        db.refresh(get_data)  
        return get_data
    
    @classmethod
    def get_by_user_filter(cls, request: dict | StudentFilter, db: Session) -> StudentBase | None:
        if isinstance(request, dict):
            filter_data = request
        else:
            filter_data = request.model_dump(exclude_none=True)
        get_user_data = db.query(cls).filter_by(**filter_data).first()
        if not get_user_data:
            return None
        return StudentBase(**get_user_data.__dict__)


