import type { EmotionState } from "@/lib/emily-api"; export interface JournalRecord { id: string; text: string; mood: string | null; responseText: string; emotionState: EmotionState | null; createdAt: string; triggers: string[]; } export interface DraftRecord { id: string; text: string; mood: string | null; createdAt: string; } export interface UserSnapshot { draft: string; mood: string | null; entries: JournalRecord[]; drafts: DraftRecord[]; } export const ACTIVE_USER_KEY = "echo-active-user"; const MAX_ENTRIES = 80; const MAX_DRAFTS = 40; export const EMPTY_SNAPSHOT: UserSnapshot = { draft: "", mood: null, entries: [], drafts: [], }; const TRIGGER_RULES: Array<{ name: string; keywords: string[] }> = [ { name: "Work Stress", keywords: ["work", "job", "office", "deadline", "boss"] }, { name: "Social Media", keywords: ["instagram", "social", "online", "scroll", "twitter"] }, { name: "Late Nights", keywords: ["late", "night", "sleep", "insomnia", "tired"] }, { name: "Unresolved Talks", keywords: ["fight", "argument", "talk", "family", "friend"] }, { name: "Financial Worry", keywords: ["money", "rent", "debt", "finance", "bills"] }, ]; function hasWindow(): boolean { return typeof window !== "undefined"; } export function getUserStorageKey(userId: string): string { return `echo-user-${userId}`; } export function getActiveUser(): string { if (!hasWindow()) return ""; return localStorage.getItem(ACTIVE_USER_KEY) ?? ""; } export function setActiveUser(userId: string): void { if (!hasWindow()) return; localStorage.setItem(ACTIVE_USER_KEY, userId); } export function clearActiveUser(): void { if (!hasWindow()) return; localStorage.removeItem(ACTIVE_USER_KEY); } export function getSnapshot(userId: string): UserSnapshot { if (!hasWindow() || !userId) return { ...EMPTY_SNAPSHOT }; const raw = localStorage.getItem(getUserStorageKey(userId)); if (!raw) return { ...EMPTY_SNAPSHOT }; try { const parsed = JSON.parse(raw) as UserSnapshot; return { draft: parsed.draft ?? "", mood: parsed.mood ?? null, entries: parsed.entries ?? [], drafts: parsed.drafts ?? [], }; } catch { return { ...EMPTY_SNAPSHOT }; } } export function saveSnapshot(userId: string, snapshot: UserSnapshot): void { if (!hasWindow() || !userId) return; localStorage.setItem(getUserStorageKey(userId), JSON.stringify(snapshot)); } export function appendEntry(snapshot: UserSnapshot, next: JournalRecord): UserSnapshot { return { ...snapshot, entries: [next, ...snapshot.entries].slice(0, MAX_ENTRIES), }; } export function appendDraft(snapshot: UserSnapshot, text: string): UserSnapshot { if (!text.trim()) return snapshot; const nextDraft: DraftRecord = { id: `draft-${Date.now()}`, text: text.trim(), mood: snapshot.mood, createdAt: new Date().toISOString(), }; return { ...snapshot, drafts: [nextDraft, ...snapshot.drafts].slice(0, MAX_DRAFTS), }; } export function deleteDraft(snapshot: UserSnapshot, draftId: string): UserSnapshot { return { ...snapshot, drafts: snapshot.drafts.filter((d) => d.id !== draftId), }; } export function extractTriggers(text: string): string[] { const normalized = text.toLowerCase(); return TRIGGER_RULES.filter((rule) => rule.keywords.some((k) => normalized.includes(k))).map((rule) => rule.name); } export function toMoodLabel(entries: JournalRecord[]): string { if (!entries.length) return "No data"; const scoreByMood: Record = { Anxious: -2, Sad: -1, Neutral: 0, Good: 1, Great: 2 }; const scored = entries.map((entry) => scoreByMood[entry.mood ?? "Neutral"] ?? 0); const avg = scored.reduce((sum, v) => sum + v, 0) / scored.length; if (avg >= 1.5) return "Great"; if (avg >= 0.5) return "Good"; if (avg > -0.5) return "Neutral"; if (avg > -1.5) return "Sad"; return "Anxious"; } export function buildInsights(entries: JournalRecord[]): string[] { if (!entries.length) return ["No insights yet. Add journal entries to unlock pattern insights."]; const averageValence = entries.reduce((sum, e) => sum + (e.emotionState?.emotional_valence ?? 0), 0) / entries.length; const triggerCounts = new Map(); for (const entry of entries) { for (const trigger of entry.triggers) { triggerCounts.set(trigger, (triggerCounts.get(trigger) ?? 0) + 1); } } const topTrigger = Array.from(triggerCounts.entries()).sort((a, b) => b[1] - a[1])[0]?.[0]; const results = [ averageValence < -0.2 ? "Trend: recent valence looks low. Try smaller recovery routines." : "Trend: recent valence is stable or improving.", `Mood trend: ${toMoodLabel(entries)}.`, ]; if (topTrigger) results.push(`Top trigger: ${topTrigger}.`); return results; } export function formatLocalDate(iso: string): string { return new Date(iso).toLocaleString(); }