export type Sm2Grade = 1 | 2 | 3 | 4 export interface Sm2State { easinessFactor: number interval: number } export interface Sm2UpdateResult extends Sm2State { nextReviewAt: Date } /** SM-2 update per US-FLASHCARDS spec (grades 1–4). */ export function computeSm2Update( grade: number, previous: Sm2State, ): Sm2UpdateResult { const g = Math.min(4, Math.max(1, Math.round(grade))) as Sm2Grade const ef = previous.easinessFactor const newEF = Math.max( 1.3, ef + 0.1 - (5 - g) * (0.08 + (5 - g) * 0.02), ) const nextInterval = g <= 2 ? 1 : Math.max(1, Math.round(previous.interval * newEF)) const nextReviewAt = new Date() nextReviewAt.setDate(nextReviewAt.getDate() + nextInterval) return { easinessFactor: newEF, interval: nextInterval, nextReviewAt, } } export function isCardMastered(interval: number): boolean { return interval >= 21 }