import type { Scene, SceneId } from '../types'; function sceneCreatedAtSortKey(sceneId: string): number { const last = sceneId.split('_').at(-1) ?? ''; const n = Number.parseInt(last, 16); return Number.isFinite(n) ? n : 0; } /** Порядок по умолчанию: новее выше (как раньше по timestamp в id). */ export function defaultSceneListOrder(scenes: Record): SceneId[] { return (Object.keys(scenes) as SceneId[]).sort( (a, b) => sceneCreatedAtSortKey(b) - sceneCreatedAtSortKey(a), ); } /** * Нормализует порядок: убирает отсутствующие id, добавляет новые в конец * (новые без записи в order — по умолчанию в «хвост» относительно сохранённого порядка; * при создании сцены мы сами prepend'им). */ export function reconcileSceneListOrder( scenes: Record, order: readonly SceneId[] | null | undefined, ): SceneId[] { const ids = new Set(Object.keys(scenes) as SceneId[]); if (ids.size === 0) return []; if (!order || order.length === 0) return defaultSceneListOrder(scenes); const seen = new Set(); const next: SceneId[] = []; for (const id of order) { if (!ids.has(id) || seen.has(id)) continue; next.push(id); seen.add(id); } for (const id of defaultSceneListOrder(scenes)) { if (seen.has(id)) continue; next.push(id); } return next; } export function prependSceneListOrder(order: readonly SceneId[], sceneId: SceneId): SceneId[] { return [sceneId, ...order.filter((id) => id !== sceneId)]; } export function removeFromSceneListOrder(order: readonly SceneId[], sceneId: SceneId): SceneId[] { return order.filter((id) => id !== sceneId); } export function moveSceneInListOrder( order: readonly SceneId[], draggedId: SceneId, targetId: SceneId, place: 'before' | 'after', ): SceneId[] { if (draggedId === targetId) return [...order]; if (!order.includes(draggedId) || !order.includes(targetId)) return [...order]; const without = order.filter((id) => id !== draggedId); const targetIndex = without.indexOf(targetId); if (targetIndex < 0) return [...order]; const insertAt = place === 'before' ? targetIndex : targetIndex + 1; const next = [...without]; next.splice(insertAt, 0, draggedId); return next; }