export interface GameStats { streak: number; lastDate: string; // ISO date YYYY-MM-DD of last solve total: number; bestTime: number; // seconds, 0 = never recorded lastTime: number; // seconds for the most recent solve (0 if none) solvedDates: string[]; // history of solved ISO dates (for heatmap) } const DEFAULT: GameStats = { streak: 0, lastDate: "", total: 0, bestTime: 0, lastTime: 0, solvedDates: [] }; function storageKey(game: string) { return `stats-${game}`; } export function loadStats(game: string): GameStats { if (typeof window === "undefined") return DEFAULT; try { const raw = localStorage.getItem(storageKey(game)); if (!raw) return DEFAULT; return { ...DEFAULT, ...JSON.parse(raw) }; } catch { return DEFAULT; } } export function recordSolve(game: string, date: string, secs: number): GameStats { const prev = loadStats(game); // Compute yesterday ISO using local-date arithmetic (avoids UTC offset bug) const [y, m, d] = date.split("-").map(Number); const prev2 = new Date(y, m - 1, d - 1); const yesterdayISO = `${prev2.getFullYear()}-${String(prev2.getMonth() + 1).padStart(2, "0")}-${String(prev2.getDate()).padStart(2, "0")}`; let streak = prev.streak; if (prev.lastDate === date) { // Already solved today — don't double-count streak } else if (prev.lastDate === yesterdayISO) { streak += 1; } else { streak = 1; } // Build solved dates history (keep last 120 days, no duplicates) const prevDates = prev.solvedDates ?? []; const solvedDates = prevDates.includes(date) ? prevDates : [...prevDates, date].slice(-120); const stats: GameStats = { streak, lastDate: date, total: prev.lastDate === date ? prev.total : prev.total + 1, bestTime: prev.bestTime === 0 || secs < prev.bestTime ? secs : prev.bestTime, lastTime: secs, solvedDates, }; localStorage.setItem(storageKey(game), JSON.stringify(stats)); return stats; } // ── Ritual streak (global: all 5 games solved in a day) ─────────────────────── export interface RitualStats { streak: number; // consecutive days with all 5 solved lastDate: string; // last day all 5 were solved } const RITUAL_KEY = "stats-ritual"; export function getRitualStreak(): RitualStats { if (typeof window === "undefined") return { streak: 0, lastDate: "" }; try { const raw = localStorage.getItem(RITUAL_KEY); return raw ? { ...{ streak: 0, lastDate: "" }, ...JSON.parse(raw) } : { streak: 0, lastDate: "" }; } catch { return { streak: 0, lastDate: "" }; } } /** Call this when all 5 games are confirmed solved today. Updates global ritual streak. */ export function updateRitualStreak(date: string): RitualStats { if (typeof window === "undefined") return { streak: 0, lastDate: "" }; const prev = getRitualStreak(); if (prev.lastDate === date) return prev; // already counted today const [y, m, d] = date.split("-").map(Number); const yesterday = new Date(y, m - 1, d - 1); const yesterdayISO = `${yesterday.getFullYear()}-${String(yesterday.getMonth() + 1).padStart(2, "0")}-${String(yesterday.getDate()).padStart(2, "0")}`; const streak = prev.lastDate === yesterdayISO ? prev.streak + 1 : 1; const updated: RitualStats = { streak, lastDate: date }; localStorage.setItem(RITUAL_KEY, JSON.stringify(updated)); return updated; }