import mongoose, { Document, Schema } from 'mongoose'; export type SudokuDifficulty = 'easy' | 'medium' | 'hard'; export type SudokuGameMode = 'standard' | 'irregular'; export interface ISudokuRecord extends Document { userId: mongoose.Types.ObjectId; username: string; fullname: string; difficulty: SudokuDifficulty; gameMode: SudokuGameMode; timeSeconds: number; won: boolean; createdAt: Date; updatedAt: Date; } export interface ISudokuLeaderboardRecord { userId: mongoose.Types.ObjectId; username: string; fullname: string; gameMode: SudokuGameMode; bestTime: number; totalGames: number; wonGames: number; winRate: number; lastPlayed: Date; } const sudokuRecordSchema = new Schema({ userId: { type: Schema.Types.ObjectId, ref: 'User', required: true }, username: { type: String, required: true }, fullname: { type: String, required: true }, difficulty: { type: String, enum: ['easy', 'medium', 'hard'], required: true }, gameMode: { type: String, enum: ['standard', 'irregular'], required: true, default: 'standard' }, timeSeconds: { type: Number, required: true, min: 0 }, won: { type: Boolean, required: true } }, { timestamps: true }); sudokuRecordSchema.index({ userId: 1, difficulty: 1, gameMode: 1 }); sudokuRecordSchema.index({ difficulty: 1, won: 1, gameMode: 1, timeSeconds: 1 }); sudokuRecordSchema.statics.getLeaderboard = function( difficulty: SudokuDifficulty, gameMode: SudokuGameMode | 'all', skipCount: number, pageSize: number ): mongoose.Aggregate { const match: any = { difficulty }; if (gameMode === 'standard') { match.$or = [ { gameMode: 'standard' }, { gameMode: { $exists: false } } ]; } else if (gameMode === 'irregular') { match.gameMode = 'irregular'; } return this.aggregate([ { $match: match }, { $group: { _id: { userId: '$userId', gameMode: { $ifNull: ['$gameMode', 'standard'] } }, username: { $first: '$username' }, fullname: { $first: '$fullname' }, gameMode: { $first: { $ifNull: ['$gameMode', 'standard'] } }, bestTime: { $min: { $cond: [{ $eq: ['$won', true] }, '$timeSeconds', null] } }, totalGames: { $sum: 1 }, wonGames: { $sum: { $cond: ['$won', 1, 0] } }, lastPlayed: { $max: '$createdAt' } } }, { $match: { bestTime: { $ne: null } } }, { $addFields: { userId: '$_id.userId', winRate: { $multiply: [ { $cond: [{ $eq: ['$totalGames', 0] }, 0, { $divide: ['$wonGames', '$totalGames'] }] }, 100 ] } } }, { $sort: { bestTime: 1 } }, { $skip: skipCount }, { $limit: pageSize } ]); }; interface SudokuRecordModel extends mongoose.Model { getLeaderboard( difficulty: SudokuDifficulty, gameMode: SudokuGameMode | 'all', skipCount: number, pageSize: number ): mongoose.Aggregate; } export const SudokuRecord = mongoose.model( 'SudokuRecord', sudokuRecordSchema );