import { getDb } from '../db/database.js' export interface DbExam { id: number user_id: number title: string subtitle: string | null exam_json: string created_at: number updated_at: number share_token: string | null is_public: number is_favorite: number tags: string | null share_mode: string | null cloned_from_share_token: string | null } export interface ExamListItem { id: number title: string subtitle: string | null created_at: number updated_at: number question_count: number share_token: string | null is_favorite: number tags: string collection_id: number | null } export function createExam(userId: number, title: string, subtitle: string | null, examJson: string, tagsJson: string = '[]'): { id: number } { const db = getDb() const result = db.prepare(` INSERT INTO saved_exams (user_id, title, subtitle, exam_json, tags) VALUES (?, ?, ?, ?, ?) `).run(userId, title, subtitle, examJson, tagsJson) return { id: result.lastInsertRowid as number } } export function getExamById(id: number, userId: number): DbExam | undefined { const db = getDb() return db.prepare('SELECT * FROM saved_exams WHERE id = ? AND user_id = ?').get(id, userId) as DbExam | undefined } export function listExamsByUser(userId: number): ExamListItem[] { const db = getDb() return db.prepare(` SELECT id, title, subtitle, created_at, updated_at, share_token, is_favorite, tags, collection_id, json_array_length(json_extract(exam_json, '$.questions')) AS question_count FROM saved_exams WHERE user_id = ? ORDER BY is_favorite DESC, updated_at DESC `).all(userId) as ExamListItem[] } export function updateExam(id: number, userId: number, title: string, subtitle: string | null, examJson: string, tagsJson: string | null = null): boolean { const db = getDb() if (tagsJson !== null) { const result = db.prepare(` UPDATE saved_exams SET title = ?, subtitle = ?, exam_json = ?, tags = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(title, subtitle, examJson, tagsJson, id, userId) return result.changes > 0 } const result = db.prepare(` UPDATE saved_exams SET title = ?, subtitle = ?, exam_json = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(title, subtitle, examJson, id, userId) return result.changes > 0 } export function deleteExam(id: number, userId: number): boolean { const db = getDb() const result = db.prepare('DELETE FROM saved_exams WHERE id = ? AND user_id = ?').run(id, userId) return result.changes > 0 } export function countExams(): number { const db = getDb() const row = db.prepare('SELECT COUNT(*) AS cnt FROM saved_exams').get() as { cnt: number } return row.cnt } export function setShareToken(id: number, userId: number, token: string, mode: string = 'clone'): boolean { const db = getDb() const result = db.prepare(` UPDATE saved_exams SET share_token = ?, is_public = 1, share_mode = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(token, mode, id, userId) return result.changes > 0 } export function clearShareToken(id: number, userId: number): boolean { const db = getDb() const result = db.prepare(` UPDATE saved_exams SET share_token = NULL, is_public = 0, share_mode = 'clone', updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(id, userId) return result.changes > 0 } export function getExamByShareToken(token: string): DbExam | undefined { const db = getDb() return db.prepare('SELECT * FROM saved_exams WHERE share_token = ? AND is_public = 1').get(token) as DbExam | undefined } export function setShareMode(id: number, userId: number, mode: string): boolean { const db = getDb() const result = db.prepare(` UPDATE saved_exams SET share_mode = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(mode, id, userId) return result.changes > 0 } export function cloneExam(userId: number, sourceExam: DbExam, shareToken: string): { id: number } { const db = getDb() const parsed = JSON.parse(sourceExam.exam_json) parsed.id = undefined const result = db.prepare(` INSERT INTO saved_exams (user_id, title, subtitle, exam_json, cloned_from_share_token) VALUES (?, ?, ?, ?, ?) `).run(userId, sourceExam.title + ' (copy)', sourceExam.subtitle, JSON.stringify(parsed), shareToken) return { id: result.lastInsertRowid as number } } export interface ClonedExamItem { id: number title: string subtitle: string | null created_at: number updated_at: number question_count: number cloned_from_share_token: string } export function listClonedExams(userId: number): ClonedExamItem[] { const db = getDb() return db.prepare(` SELECT id, title, subtitle, created_at, updated_at, cloned_from_share_token, json_array_length(json_extract(exam_json, '$.questions')) AS question_count FROM saved_exams WHERE user_id = ? AND cloned_from_share_token IS NOT NULL ORDER BY updated_at DESC `).all(userId) as ClonedExamItem[] } export function setFavorite(id: number, userId: number, isFavorite: boolean): boolean { const db = getDb() const result = db.prepare(` UPDATE saved_exams SET is_favorite = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(isFavorite ? 1 : 0, id, userId) return result.changes > 0 } export function getExamRawJson(id: number, userId: number): { title: string; exam_json: string } | undefined { const db = getDb() return db.prepare('SELECT title, exam_json FROM saved_exams WHERE id = ? AND user_id = ?').get(id, userId) as { title: string; exam_json: string } | undefined } export function duplicateOwnExam(userId: number, sourceExam: DbExam): { id: number } { const db = getDb() const parsed = JSON.parse(sourceExam.exam_json) parsed.id = undefined const result = db.prepare(` INSERT INTO saved_exams (user_id, title, subtitle, exam_json, tags) VALUES (?, ?, ?, ?, ?) `).run(userId, sourceExam.title + ' (copy)', sourceExam.subtitle, JSON.stringify(parsed), sourceExam.tags ?? '[]') return { id: result.lastInsertRowid as number } } export function setExamCollection(id: number, userId: number, collectionId: number | null): boolean { const db = getDb() const result = db.prepare(` UPDATE saved_exams SET collection_id = ?, updated_at = unixepoch() WHERE id = ? AND user_id = ? `).run(collectionId, id, userId) return result.changes > 0 }