/**
 * Canvas Settings Store
 *
 * Jotai atoms for managing canvas settings with localStorage persistence.
 * Uses atomWithStorage for automatic sync across tabs.
 *
 * Built-in presets and utility functions are in ./settings-presets.ts
 */

import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';
import {
	type CanvasSettingsState,
	type EventActionMapping,
	type SettingsPreset,
	CanvasEventType,
	DEFAULT_MAPPINGS,
	BuiltInActionId,
} from './settings-types';
import { createDebug } from '../utils/debug';

// Re-export presets and utility for backward compat
export { BUILT_IN_PRESETS, getActionForEvent } from './settings-presets';
import { BUILT_IN_PRESETS } from './settings-presets';

const debug = createDebug('settings');

// =============================================================================
// Default State
// =============================================================================

const DEFAULT_STATE: CanvasSettingsState = {
	mappings: DEFAULT_MAPPINGS,
	activePresetId: 'default',
	customPresets: [],
	isPanelOpen: false,
	virtualizationEnabled: true,
};

// =============================================================================
// Main Settings Atom (persisted)
// =============================================================================

/**
 * The main settings atom, persisted to localStorage.
 * All settings state is stored in a single atom for atomic updates.
 */
export const canvasSettingsAtom = atomWithStorage<CanvasSettingsState>(
	'@blinksgg/canvas/settings',
	DEFAULT_STATE
);

// =============================================================================
// Derived Read-Only Atoms
// =============================================================================

/**
 * Current event-action mappings.
 */
export const eventMappingsAtom = atom((get) => get(canvasSettingsAtom).mappings);

/**
 * Currently active preset ID (null if mappings have been modified).
 */
export const activePresetIdAtom = atom((get) => get(canvasSettingsAtom).activePresetId);

/**
 * All presets (built-in + custom).
 */
export const allPresetsAtom = atom((get) => {
	const state = get(canvasSettingsAtom);
	return [...BUILT_IN_PRESETS, ...state.customPresets];
});

/**
 * The currently active preset (if any).
 */
export const activePresetAtom = atom((get) => {
	const presetId = get(activePresetIdAtom);
	if (!presetId) return null;
	const allPresets = get(allPresetsAtom);
	return allPresets.find((p) => p.id === presetId) || null;
});

/**
 * Whether the settings panel is open.
 */
export const isPanelOpenAtom = atom((get) => get(canvasSettingsAtom).isPanelOpen);

/**
 * Whether viewport virtualization is enabled.
 * When true, only visible nodes/edges are rendered (better performance for large graphs).
 */
export const virtualizationEnabledAtom = atom(
	(get) => get(canvasSettingsAtom).virtualizationEnabled ?? true
);

/**
 * Whether current mappings differ from the active preset.
 */
export const hasUnsavedChangesAtom = atom((get) => {
	const state = get(canvasSettingsAtom);
	const activePreset = get(activePresetAtom);

	if (!activePreset) return true;

	// Compare mappings
	const events = Object.values(CanvasEventType);
	return events.some((event) => state.mappings[event] !== activePreset.mappings[event]);
});

// =============================================================================
// Action Atoms (write-only)
// =============================================================================

/**
 * Set a single event-action mapping.
 */
export const setEventMappingAtom = atom(
	null,
	(get, set, { event, actionId }: { event: CanvasEventType; actionId: string }) => {
		const current = get(canvasSettingsAtom);
		set(canvasSettingsAtom, {
			...current,
			mappings: {
				...current.mappings,
				[event]: actionId,
			},
			// Clear active preset since mappings have changed
			activePresetId: null,
		});
	}
);

/**
 * Apply a preset (copies its mappings to current).
 */
export const applyPresetAtom = atom(null, (get, set, presetId: string) => {
	const allPresets = get(allPresetsAtom);
	const preset = allPresets.find((p) => p.id === presetId);

	if (!preset) {
		debug.warn('Preset not found: %s', presetId);
		return;
	}

	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		mappings: { ...preset.mappings },
		activePresetId: presetId,
	});
});

/**
 * Save current mappings as a new custom preset.
 */
export const saveAsPresetAtom = atom(
	null,
	(get, set, { name, description }: { name: string; description?: string }) => {
		const current = get(canvasSettingsAtom);

		// Generate unique ID
		const id = `custom-${Date.now()}`;

		const newPreset: SettingsPreset = {
			id,
			name,
			description,
			mappings: { ...current.mappings },
			isBuiltIn: false,
		};

		set(canvasSettingsAtom, {
			...current,
			customPresets: [...current.customPresets, newPreset],
			activePresetId: id,
		});

		return id;
	}
);

/**
 * Update an existing custom preset with current mappings.
 */
export const updatePresetAtom = atom(null, (get, set, presetId: string) => {
	const current = get(canvasSettingsAtom);

	// Can only update custom presets
	const presetIndex = current.customPresets.findIndex((p) => p.id === presetId);
	if (presetIndex === -1) {
		debug.warn('Cannot update preset: %s (not found or built-in)', presetId);
		return;
	}

	const updatedPresets = [...current.customPresets];
	updatedPresets[presetIndex] = {
		...updatedPresets[presetIndex],
		mappings: { ...current.mappings },
	};

	set(canvasSettingsAtom, {
		...current,
		customPresets: updatedPresets,
		activePresetId: presetId,
	});
});

/**
 * Delete a custom preset.
 */
export const deletePresetAtom = atom(null, (get, set, presetId: string) => {
	const current = get(canvasSettingsAtom);

	// Can only delete custom presets
	const newCustomPresets = current.customPresets.filter((p) => p.id !== presetId);

	if (newCustomPresets.length === current.customPresets.length) {
		debug.warn('Cannot delete preset: %s (not found or built-in)', presetId);
		return;
	}

	// If we deleted the active preset, switch to default
	const newActiveId = current.activePresetId === presetId ? 'default' : current.activePresetId;

	// If switching to default, also reset mappings
	const newMappings = newActiveId === 'default' ? DEFAULT_MAPPINGS : current.mappings;

	set(canvasSettingsAtom, {
		...current,
		customPresets: newCustomPresets,
		activePresetId: newActiveId,
		mappings: newMappings,
	});
});

/**
 * Reset to default settings.
 */
export const resetSettingsAtom = atom(null, (get, set) => {
	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		mappings: DEFAULT_MAPPINGS,
		activePresetId: 'default',
	});
});

/**
 * Toggle the settings panel open/closed.
 */
export const togglePanelAtom = atom(null, (get, set) => {
	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		isPanelOpen: !current.isPanelOpen,
	});
});

/**
 * Set the panel open state directly.
 */
export const setPanelOpenAtom = atom(null, (get, set, isOpen: boolean) => {
	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		isPanelOpen: isOpen,
	});
});

/**
 * Set virtualization enabled/disabled.
 */
export const setVirtualizationEnabledAtom = atom(null, (get, set, enabled: boolean) => {
	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		virtualizationEnabled: enabled,
	});
});

/**
 * Toggle virtualization on/off.
 */
export const toggleVirtualizationAtom = atom(null, (get, set) => {
	const current = get(canvasSettingsAtom);
	set(canvasSettingsAtom, {
		...current,
		virtualizationEnabled: !(current.virtualizationEnabled ?? true),
	});
});

