import { createSampleData } from './sampleData' import type { AppStateV1, LearningGoal, LearningTask, LoadResult, Priority, TaskStatus } from './types' export const STORAGE_KEY = 'learning-planner.state' const priorities: Priority[] = ['low', 'medium', 'high'] const statuses: TaskStatus[] = ['todo', 'in-progress', 'done'] function isString(value: unknown): value is string { return typeof value === 'string' } function isGoal(value: unknown): value is LearningGoal { if (!value || typeof value !== 'object') return false const goal = value as Record return ['id', 'title', 'description', 'category', 'targetDate', 'color', 'createdAt'].every((key) => isString(goal[key])) } function isTask(value: unknown): value is LearningTask { if (!value || typeof value !== 'object') return false const task = value as Record return ( ['id', 'goalId', 'title', 'notes', 'dueDate', 'createdAt'].every((key) => isString(task[key])) && priorities.includes(task.priority as Priority) && statuses.includes(task.status as TaskStatus) && typeof task.estimatedMinutes === 'number' && Number.isFinite(task.estimatedMinutes) && task.estimatedMinutes >= 0 ) } export function parseState(value: unknown): AppStateV1 { if (!value || typeof value !== 'object') throw new Error('The backup must contain an object.') const state = value as Record if (state.version !== 1) throw new Error('This backup version is not supported.') if (!Array.isArray(state.goals) || !state.goals.every(isGoal)) throw new Error('The backup contains invalid goals.') if (!Array.isArray(state.tasks) || !state.tasks.every(isTask)) throw new Error('The backup contains invalid tasks.') const goalIds = new Set(state.goals.map((goal) => goal.id)) if (state.tasks.some((task) => !goalIds.has(task.goalId))) throw new Error('A task refers to a goal that does not exist.') return state as unknown as AppStateV1 } export const storageAdapter = { load(storage: Pick = localStorage): LoadResult { try { const raw = storage.getItem(STORAGE_KEY) if (!raw) return { state: createSampleData() } return { state: parseState(JSON.parse(raw)) } } catch (error) { return { state: createSampleData(), warning: `Saved data could not be read. Sample data was restored. ${error instanceof Error ? error.message : ''}`.trim(), } } }, save(state: AppStateV1, storage: Pick = localStorage): void { storage.setItem(STORAGE_KEY, JSON.stringify(parseState(state))) }, export(state: AppStateV1): string { return JSON.stringify(parseState(state), null, 2) }, import(raw: string): AppStateV1 { return parseState(JSON.parse(raw)) }, }