import { Exam } from "@/interfaces/exam"; import { diff, Diff } from "deep-diff"; const EXCLUDED_FIELDS = new Set(["_id", "id", "createdAt", "createdBy", "entities", "isDiagnostic", "private"]); export function generateExamDifferences(oldExam: Exam, newExam: Exam): string[] { const differences = diff(oldExam, newExam) || []; return differences.map((change) => formatDifference(change)).filter(Boolean) as string[]; } function formatDifference(change: Diff): string | undefined { if (!change.path) { return; } if (change.path.some((segment) => EXCLUDED_FIELDS.has(segment))) { return; } // Convert path array to something human-readable const pathString = change.path.join(" \u2192 "); // e.g. "parts → 0 → exercises → 1 → prompt" switch (change.kind) { case "N": // A new property/element was added return `\u{2022} Added \`${pathString}\` with value: ${formatValue(change.rhs)}`; case "D": // A property/element was deleted return `\u{2022} Removed \`${pathString}\` which had value: ${formatValue(change.lhs)}`; case "E": // A property/element was edited return `\u{2022} Changed \`${pathString}\` from ${formatValue(change.lhs)} to ${formatValue(change.rhs)}`; case "A": // An array change; change.item describes what happened at array index change.index return formatArrayChange(change); default: return; } } function formatArrayChange(change: Diff): string | undefined { if (!change.path) return; if (change.path.some((segment) => EXCLUDED_FIELDS.has(segment))) { return; } const pathString = change.path.join(" \u2192 "); const arrayChange = (change as any).item; const idx = (change as any).index; if (!arrayChange) return; switch (arrayChange.kind) { case "N": return `\u{2022} Added an item at index [${idx}] in \`${pathString}\`: ${formatValue(arrayChange.rhs)}`; case "D": return `\u{2022} Removed an item at index [${idx}] in \`${pathString}\`: ${formatValue(arrayChange.lhs)}`; case "E": return `\u{2022} Edited an item at index [${idx}] in \`${pathString}\` from ${formatValue(arrayChange.lhs)} to ${formatValue(arrayChange.rhs)}`; case "A": // Nested array changes could happen theoretically; handle or ignore similarly return `\u{2022} Complex array change at index [${idx}] in \`${pathString}\`: ${JSON.stringify(arrayChange)}`; default: return; } } function formatValue(value: any): string { if (value === null) return "null"; if (value === undefined) return "undefined"; if (typeof value === "object") { try { return JSON.stringify(value); } catch { return String(value); } } return JSON.stringify(value); }