// DistractIQ deterministic prediction engine // Implements the spec formulas exactly. export interface FocusInputs { study_hours: number; phone_hours: number; social_hours: number; sleep_hours: number; stress_level: number; // 1-10 notifications: number; } export interface FocusOutputs { distraction_score: number; productivity: number; focus_score: number; risk: "HIGH" | "LOW"; risk_reasons: string[]; xp_gained: number; deep_focus_hours: number; advisories: string[]; persona: { title: string; caption: string; emoji: string }; } const clamp = (v: number, min: number, max: number) => Math.max(min, Math.min(max, v)); export function computeDistraction(i: FocusInputs): number { const raw = i.phone_hours * 8 + i.social_hours * 12 + i.notifications / 10 + i.stress_level * 5; return Math.round(clamp(raw, 0, 100)); } export function computeProductivity(i: FocusInputs): number { const raw = i.study_hours * 15 + i.sleep_hours * 5 - (i.phone_hours * 4 + i.social_hours * 6 + i.stress_level * 8) + 30; return Math.round(clamp(raw, 0, 100)); } export function computeFocusScore(distraction: number, productivity: number): number { // Half-doughnut: invert distraction, weight productivity return Math.round(clamp(productivity * 0.6 + (100 - distraction) * 0.4, 0, 100)); } export function computeRisk(i: FocusInputs, distraction: number): { risk: "HIGH" | "LOW"; reasons: string[] } { const reasons: string[] = []; if (i.phone_hours > 6 && i.study_hours < 3) reasons.push("Phone use exceeds 6h with under 3h of study"); if (i.social_hours > 4) reasons.push("Social media exceeds 4h"); if (i.stress_level > 8 && i.sleep_hours < 5) reasons.push("High stress combined with sleep deprivation"); if (distraction > 65) reasons.push("Distraction Score above critical threshold (65)"); return { risk: reasons.length > 0 ? "HIGH" : "LOW", reasons }; } export function computeAdvisories(i: FocusInputs): string[] { const out: string[] = []; if (i.stress_level > 7) out.push("Stress is blocking your deep work capacity."); if (i.sleep_hours < 6) out.push("Sleep deprivation is a hidden productivity killer."); if (i.notifications > 150) out.push("Your notification density is triggering severe context-switching."); if (i.phone_hours > 6) out.push("Excessive phone time is fragmenting your attention."); if (i.social_hours > 4) out.push("Social media is the leading cause of dopamine loops today."); return out; } export function derivePersona(focus: number, productivity: number, distraction: number): { title: string; caption: string; emoji: string } { if (focus >= 80) return { title: "Deep Work Ninja", emoji: "🥷", caption: "Silent. Focused. Untouchable. You operate in flow others only read about." }; if (focus >= 65) return { title: "Momentum Maker", emoji: "🚀", caption: "Solid rhythm — protect your peak hours and you'll hit elite tier." }; if (productivity >= 50 && distraction < 50) return { title: "Balanced Builder", emoji: "⚖️", caption: "You're stitching focus and rest together — keep refining the edges." }; if (distraction >= 70) return { title: "Scroll Hostage", emoji: "🪤", caption: "The feed is winning. Time to reclaim the next 25 minutes." }; if (productivity < 35) return { title: "Drift Mode", emoji: "🌫️", caption: "Low signal day. One small block of deep work resets the whole week." }; return { title: "Focus Apprentice", emoji: "🎯", caption: "Building the habit. Small, repeatable wins compound fast." }; } export function computeAll(i: FocusInputs): FocusOutputs { const distraction = computeDistraction(i); const productivity = computeProductivity(i); const focus = computeFocusScore(distraction, productivity); const { risk, reasons } = computeRisk(i, distraction); const xp = Math.max(0, Math.round(productivity / 3)); return { distraction_score: distraction, productivity, focus_score: focus, risk, risk_reasons: reasons, xp_gained: xp, deep_focus_hours: Math.round(i.study_hours * (productivity / 100) * 10) / 10, advisories: computeAdvisories(i), persona: derivePersona(focus, productivity, distraction), }; } // Constraint validation export function validateConstraints(i: FocusInputs): string[] { const errors: string[] = []; if (i.study_hours + i.phone_hours + i.sleep_hours > 24) { errors.push("Study + Phone + Sleep cannot exceed 24 hours."); } if (i.social_hours > i.phone_hours) { errors.push("Social media hours cannot exceed total phone hours."); } return errors; } // XP / level helpers export const XP_PER_LEVEL = 500; export const levelFromXp = (xp: number) => Math.floor(xp / XP_PER_LEVEL) + 1; export const xpInLevel = (xp: number) => xp % XP_PER_LEVEL; export function isNightMode(): boolean { const hour = new Date().getHours(); return hour >= 22 || hour < 5; }