package training import ( "context" "encoding/json" "time" "github.com/google/uuid" ) // CreateQuizQuestion creates a new quiz question func (s *Store) CreateQuizQuestion(ctx context.Context, q *QuizQuestion) error { q.ID = uuid.New() q.CreatedAt = time.Now().UTC() if !q.IsActive { q.IsActive = true } options, _ := json.Marshal(q.Options) _, err := s.pool.Exec(ctx, ` INSERT INTO training_quiz_questions ( id, module_id, question, options, correct_index, explanation, difficulty, is_active, sort_order, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) `, q.ID, q.ModuleID, q.Question, options, q.CorrectIndex, q.Explanation, string(q.Difficulty), q.IsActive, q.SortOrder, q.CreatedAt, ) return err } // ListQuizQuestions lists quiz questions for a module func (s *Store) ListQuizQuestions(ctx context.Context, moduleID uuid.UUID) ([]QuizQuestion, error) { rows, err := s.pool.Query(ctx, ` SELECT id, module_id, question, options, correct_index, explanation, difficulty, is_active, sort_order, created_at FROM training_quiz_questions WHERE module_id = $1 AND is_active = true ORDER BY sort_order ASC, created_at ASC `, moduleID) if err != nil { return nil, err } defer rows.Close() var questions []QuizQuestion for rows.Next() { var q QuizQuestion var options []byte var difficulty string err := rows.Scan( &q.ID, &q.ModuleID, &q.Question, &options, &q.CorrectIndex, &q.Explanation, &difficulty, &q.IsActive, &q.SortOrder, &q.CreatedAt, ) if err != nil { return nil, err } q.Difficulty = Difficulty(difficulty) json.Unmarshal(options, &q.Options) if q.Options == nil { q.Options = []string{} } questions = append(questions, q) } if questions == nil { questions = []QuizQuestion{} } return questions, nil } // CreateQuizAttempt records a quiz attempt func (s *Store) CreateQuizAttempt(ctx context.Context, attempt *QuizAttempt) error { attempt.ID = uuid.New() attempt.AttemptedAt = time.Now().UTC() answers, _ := json.Marshal(attempt.Answers) _, err := s.pool.Exec(ctx, ` INSERT INTO training_quiz_attempts ( id, assignment_id, user_id, answers, score, passed, correct_count, total_count, duration_seconds, attempted_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) `, attempt.ID, attempt.AssignmentID, attempt.UserID, answers, attempt.Score, attempt.Passed, attempt.CorrectCount, attempt.TotalCount, attempt.DurationSeconds, attempt.AttemptedAt, ) return err } // ListQuizAttempts lists quiz attempts for an assignment func (s *Store) ListQuizAttempts(ctx context.Context, assignmentID uuid.UUID) ([]QuizAttempt, error) { rows, err := s.pool.Query(ctx, ` SELECT id, assignment_id, user_id, answers, score, passed, correct_count, total_count, duration_seconds, attempted_at FROM training_quiz_attempts WHERE assignment_id = $1 ORDER BY attempted_at DESC `, assignmentID) if err != nil { return nil, err } defer rows.Close() var attempts []QuizAttempt for rows.Next() { var a QuizAttempt var answers []byte err := rows.Scan( &a.ID, &a.AssignmentID, &a.UserID, &answers, &a.Score, &a.Passed, &a.CorrectCount, &a.TotalCount, &a.DurationSeconds, &a.AttemptedAt, ) if err != nil { return nil, err } json.Unmarshal(answers, &a.Answers) if a.Answers == nil { a.Answers = []QuizAnswer{} } attempts = append(attempts, a) } if attempts == nil { attempts = []QuizAttempt{} } return attempts, nil }