import { Note, NoteAccessLog, NotePrediction } from '../types'; /** * Simulates finding the dominant frequency in access logs for a specific note * returning the period in days. */ export function detectAccessCycle(logs: NoteAccessLog[]): number | null { if (logs.length < 5) return null; const accessDays = logs .map(log => new Date(log.accessedAt).getTime()) .sort((a, b) => a - b); const intervals: number[] = []; for (let i = 1; i < accessDays.length; i++) { intervals.push((accessDays[i] - accessDays[i - 1]) / (1000 * 60 * 60 * 24)); } // Simple heuristic: if intervals are consistently around a value, that's our cycle // We'll calculate the median interval const sortedIntervals = [...intervals].sort((a, b) => a - b); const median = sortedIntervals[Math.floor(sortedIntervals.length / 2)]; // Check if enough intervals are close to median const withinThreshold = intervals.filter(v => Math.abs(v - median) < Math.max(2, median * 0.2)); if (withinThreshold.length >= intervals.length * 0.6) { return median; } return null; } export function predictNextAccess(note: Note, logs: NoteAccessLog[]): NotePrediction | null { const cycleDays = detectAccessCycle(logs); if (!cycleDays) return null; const lastAccess = new Date(logs[logs.length - 1].accessedAt); const nextAccessDate = new Date(lastAccess.getTime() + cycleDays * 24 * 60 * 60 * 1000); const now = new Date(); const daysUntilNext = (nextAccessDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24); // Only predict if it's coming up in the next 2 weeks if (daysUntilNext > 0 && daysUntilNext < 14) { return { noteId: note.id, predictedRelevanceDate: nextAccessDate.toISOString(), confidence: 0.7, reason: `Historical access pattern suggests a ${Math.round(cycleDays)}-day cycle.`, generatedAt: now.toISOString() }; } return null; } export function getCoaccessedNotes(baseNoteId: string, logs: NoteAccessLog[], allNotes: Note[]): Note[] { const WINDOW_MS = 30 * 60 * 1000; // 30 minutes const baseNoteLogs = logs.filter(l => l.noteId === baseNoteId); const coaccessedIds = new Set(); baseNoteLogs.forEach(baseLog => { const baseTime = new Date(baseLog.accessedAt).getTime(); logs.forEach(otherLog => { if (otherLog.noteId === baseNoteId) return; const otherTime = new Date(otherLog.accessedAt).getTime(); if (Math.abs(baseTime - otherTime) < WINDOW_MS) { coaccessedIds.add(otherLog.noteId); } }); }); return allNotes.filter(n => coaccessedIds.has(n.id)); }