from __future__ import annotations from datetime import datetime from typing import List, Optional, Dict from pydantic import BaseModel, EmailStr, Field from pydantic.config import ConfigDict from app.models import ModuleType, ProgressStatus, QuestionType class TokenPair(BaseModel): access_token: str refresh_token: str token_type: str = "bearer" class TokenRefresh(BaseModel): refresh_token: str class UserCreate(BaseModel): email: EmailStr password: str = Field(min_length=6) class UserOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int email: EmailStr role: str is_active: bool picture_url: Optional[str] = None class AdminUserOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int email: EmailStr role: str is_active: bool oauth_provider: Optional[str] = None oauth_subject: Optional[str] = None picture_url: Optional[str] = None created_at: datetime class AdminUserUpdate(BaseModel): role: Optional[str] = None is_active: Optional[bool] = None class CourseCreate(BaseModel): title: str description: Optional[str] = None is_published: bool = False class CourseUpdate(BaseModel): title: Optional[str] = None description: Optional[str] = None is_published: Optional[bool] = None class AdminCourseCreate(CourseCreate): group_ids: List[int] = [] class AdminCourseUpdate(CourseUpdate): group_ids: Optional[List[int]] = None class CourseOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int title: str description: Optional[str] = None is_published: bool created_at: datetime updated_at: datetime class AdminCourseOut(CourseOut): group_ids: List[int] = [] class ModuleCreate(BaseModel): order_index: int type: ModuleType title: str content_text: Optional[str] = None pass_score: Optional[int] = 80 upload_id: Optional[int] = None class ModuleUpdate(BaseModel): order_index: Optional[int] = None type: Optional[ModuleType] = None title: Optional[str] = None content_text: Optional[str] = None pass_score: Optional[int] = None upload_id: Optional[int] = None class QuizChoiceCreate(BaseModel): text: str is_correct: bool = False class QuizChoiceOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int text: str is_correct: bool class QuizChoicePublic(BaseModel): model_config = ConfigDict(from_attributes=True) id: int text: str class QuizQuestionCreate(BaseModel): prompt: str question_type: QuestionType = QuestionType.mcq choices: List[QuizChoiceCreate] class QuizQuestionUpdate(BaseModel): prompt: Optional[str] = None question_type: Optional[QuestionType] = None choices: Optional[List[QuizChoiceCreate]] = None class QuizQuestionOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int prompt: str question_type: QuestionType choices: List[QuizChoiceOut] class QuizQuestionPublic(BaseModel): model_config = ConfigDict(from_attributes=True) id: int prompt: str question_type: QuestionType choices: List[QuizChoicePublic] class ModuleOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int course_id: int order_index: int type: ModuleType title: str content_text: Optional[str] = None pass_score: Optional[int] = None upload_id: Optional[int] = None created_at: datetime questions: List[QuizQuestionOut] = [] class ModuleProgressOut(BaseModel): model_config = ConfigDict(from_attributes=True) module_id: int status: ProgressStatus completed_at: Optional[datetime] = None score: Optional[float] = None class ModuleWithProgress(BaseModel): model_config = ConfigDict(from_attributes=True) id: int order_index: int type: ModuleType title: str content_text: Optional[str] = None pass_score: Optional[int] = None upload_id: Optional[int] = None status: ProgressStatus completed_at: Optional[datetime] = None score: Optional[float] = None questions: List[QuizQuestionPublic] = [] class CourseWithModules(BaseModel): model_config = ConfigDict(from_attributes=True) id: int title: str description: Optional[str] = None is_published: bool modules: List[ModuleWithProgress] class QuizSubmit(BaseModel): answers: Dict[int, int] class QuizResult(BaseModel): score: float passed: bool class EnrollOut(BaseModel): course_id: int enrolled_at: datetime class ProgressCourse(BaseModel): course_id: int title: str percent: float status: str final_exam_score: Optional[float] = None final_exam_passed: Optional[bool] = None completed_at: Optional[datetime] = None class ProgressOut(BaseModel): courses: List[ProgressCourse] class GroupCreate(BaseModel): name: str class GroupUpdate(BaseModel): name: Optional[str] = None class GroupOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str created_at: datetime class GroupMemberAdd(BaseModel): user_id: Optional[int] = None email: Optional[EmailStr] = None class UploadOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int filename: str content_type: str size_bytes: int created_at: datetime class AchievementOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int code: str name: str description: Optional[str] = None earned_at: Optional[datetime] = None earned: bool = False