from datetime import datetime, date from enum import Enum from typing import List, Optional, Dict, Any from uuid import UUID, uuid4 from sqlmodel import Field, SQLModel, Relationship, JSON # --- ENUMS --- class ClassEnum(str, Enum): ELEVENTH = "11" TWELFTH = "12" DROPPER = "Dropper" class ExamEnum(str, Enum): JEE_MAIN = "JEE_Main" JEE_ADVANCED = "JEE_Advanced" NEET = "NEET" JEE_NEET = "JEE_NEET" class MediumEnum(str, Enum): ENGLISH = "English" HINDI = "Hindi" BILINGUAL = "Bilingual" class TierEnum(str, Enum): FREE = "Free" PRO = "Pro" AI_COACH = "AI Coach" class QuestionTypeEnum(str, Enum): MCQ_SINGLE = "MCQ_Single" MCQ_MULTIPLE = "MCQ_Multiple" NUMERICAL = "Numerical" class SourceTypeEnum(str, Enum): DPS = "DPS" TEST = "Test" MICROTEST = "MicroTest" class ErrorTypeEnum(str, Enum): CONCEPTUAL = "Conceptual" CALCULATION = "Calculation" READING = "Reading" TIME_PRESSURE = "Time_Pressure" # --- CORE DB MODELS --- class User(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) email: Optional[str] = Field(default=None, unique=True) phone: Optional[str] = Field(default=None, unique=True) password_hash: str name: str student_class: ClassEnum = Field(alias="class") target_exam: ExamEnum medium: MediumEnum school: Optional[str] = None city: str state: str tier: TierEnum = Field(default=TierEnum.FREE) trial_end: Optional[datetime] = None subscription_end: Optional[datetime] = None profile_image_url: Optional[str] = None streak_count: int = Field(default=0) longest_streak: int = Field(default=0) created_at: datetime = Field(default_factory=datetime.utcnow) last_active: datetime = Field(default_factory=datetime.utcnow) active_session_token: Optional[str] = None class Parent(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) email: str phone: str password_hash: str name: str language: str = Field(default="English") # e.g., Hindi, English linked_students: List[str] = Field(default=[], sa_type=JSON) created_at: datetime = Field(default_factory=datetime.utcnow) class Question(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) subject: str # Physics, Chemistry, Maths, Biology topic: str subtopic: str difficulty: str # Easy, Medium, Hard type: QuestionTypeEnum question_text: str question_text_hi: Optional[str] = None options: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON) options_hi: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON) correct_answer: Dict[str, Any] = Field(sa_type=JSON) solution_text: str solution_text_hi: Optional[str] = None language: MediumEnum year: Optional[int] = None exam: Optional[ExamEnum] = None tags: Optional[str] = None is_active: bool = Field(default=True) created_by: UUID verified_by: Optional[UUID] = None class DPS(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) date: date title: str questions: List[str] = Field(default=[], sa_type=JSON) # Array of question UUID strings difficulty: str time_limit: int is_active: bool = Field(default=True) created_by: UUID class Test(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) title: str type: str # Weekly, Mock, PYQ exam_pattern: ExamEnum sections: Dict[str, Any] = Field(sa_type=JSON) # Array of {name, questions[], time_limit} total_time: int difficulty: str scheduled_date: Optional[datetime] = None end_date: Optional[datetime] = None is_active: bool = Field(default=True) created_by: UUID class Transaction(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) user_id: UUID = Field(foreign_key="user.id") amount: float tier: str status: str created_at: datetime = Field(default_factory=datetime.utcnow) class Coupon(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) code: str = Field(unique=True, index=True) discount_percent: float max_discount_amount: float is_active: bool = Field(default=True) expires_at: Optional[datetime] = None created_at: datetime = Field(default_factory=datetime.utcnow) class Attempt(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) user_id: UUID = Field(foreign_key="user.id") source_type: SourceTypeEnum source_id: UUID started_at: datetime submitted_at: Optional[datetime] = None time_taken: Optional[int] = None # in seconds answers: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON) # Array of {question_id, selected_answer, is_correct, time_spent} score: int = Field(default=0) total_questions: int accuracy: float = Field(default=0.0) status: str = Field(default="In_Progress") # In_Progress, Submitted, Timed_Out is_retake: bool = Field(default=False) class Mistake(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) user_id: UUID = Field(foreign_key="user.id") question_id: UUID = Field(foreign_key="question.id") attempt_id: UUID = Field(foreign_key="attempt.id") error_type: ErrorTypeEnum topic: str subtopic: str next_review: datetime review_count: int = Field(default=0) consecutive_correct: int = Field(default=0) is_mastered: bool = Field(default=False) created_at: datetime = Field(default_factory=datetime.utcnow) class StudyPlan(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) user_id: UUID = Field(foreign_key="user.id") date: date tasks: Dict[str, Any] = Field(sa_type=JSON) # Array of {type, description, duration_minutes, status} is_completed: bool = Field(default=False) generated_at: datetime = Field(default_factory=datetime.utcnow) feedback: Optional[str] = None class Subscription(SQLModel, table=True): id: UUID = Field(default_factory=uuid4, primary_key=True) user_id: UUID = Field(foreign_key="user.id") tier: TierEnum billing_cycle: str # Monthly, Quarterly, Annual start_date: datetime end_date: datetime amount: int # Stored in Paise (INR) payment_id: str # Razorpay order ID / payment ID status: str # Active, Expired, Cancelled, Paused auto_renew: bool = Field(default=True) coupon_code: Optional[str] = None class SystemSettings(SQLModel, table=True): id: str = Field(default="global", primary_key=True) maintenance_mode: bool = Field(default=False) allow_new_registrations: bool = Field(default=True) enable_free_trial: bool = Field(default=True) trial_duration_days: int = Field(default=5) trial_tier: TierEnum = Field(default=TierEnum.AI_COACH) updated_at: datetime = Field(default_factory=datetime.utcnow)