/**
 * Gesture Rule Store
 *
 * Jotai atoms for managing gesture rules with localStorage persistence.
 * Provides CRUD operations and an indexed lookup for fast resolution.
 */

import { atom } from 'jotai';
import { atomWithStorage } from 'jotai/utils';
import {
	type GestureRule,
	type GestureRuleIndex,
	DEFAULT_GESTURE_RULES,
	buildRuleIndex,
	mergeRules,
} from './gesture-rules';

// =============================================================================
// Persisted State
// =============================================================================

export interface GestureRuleState {
	/** User's custom rule overrides (merged with defaults at runtime) */
	customRules: GestureRule[];
	/** Whether palm rejection is enabled */
	palmRejection: boolean;
}

const DEFAULT_RULE_STATE: GestureRuleState = {
	customRules: [],
	palmRejection: true,
};

/**
 * Persisted gesture rule settings.
 * Only stores user customizations — defaults are applied at runtime.
 */
export const gestureRuleSettingsAtom = atomWithStorage<GestureRuleState>(
	'canvas-gesture-rules',
	DEFAULT_RULE_STATE,
);

// =============================================================================
// Runtime Rules (merged defaults + custom)
// =============================================================================

/**
 * Consumer-provided rule overrides (set via Canvas props).
 * These are NOT persisted — they come from the component tree.
 */
export const consumerGestureRulesAtom = atom<GestureRule[]>([]);

/**
 * The effective rule set: defaults + persisted custom + consumer overrides.
 * Consumer rules take highest priority (applied last).
 */
export const gestureRulesAtom = atom((get) => {
	const settings = get(gestureRuleSettingsAtom);
	const consumerRules = get(consumerGestureRulesAtom);

	// Layer 1: Start with defaults
	// Layer 2: Apply persisted user customizations
	let rules = mergeRules(DEFAULT_GESTURE_RULES, settings.customRules);
	// Layer 3: Apply consumer-provided overrides
	if (consumerRules.length > 0) {
		rules = mergeRules(rules, consumerRules);
	}

	return rules;
});

/**
 * Indexed rule set for fast resolution.
 * Recomputes only when rules change.
 */
export const gestureRuleIndexAtom = atom<GestureRuleIndex>((get) => {
	return buildRuleIndex(get(gestureRulesAtom));
});

/**
 * Palm rejection toggle.
 */
export const palmRejectionEnabledAtom = atom(
	(get) => get(gestureRuleSettingsAtom).palmRejection,
	(get, set, enabled: boolean) => {
		const current = get(gestureRuleSettingsAtom);
		set(gestureRuleSettingsAtom, { ...current, palmRejection: enabled });
	},
);

// =============================================================================
// CRUD Atoms
// =============================================================================

/**
 * Add or replace a custom gesture rule.
 * If a rule with the same ID exists, it's replaced.
 */
export const addGestureRuleAtom = atom(null, (get, set, rule: GestureRule) => {
	const current = get(gestureRuleSettingsAtom);
	const existing = current.customRules.findIndex((r) => r.id === rule.id);

	const newRules = [...current.customRules];
	if (existing >= 0) {
		newRules[existing] = rule;
	} else {
		newRules.push(rule);
	}

	set(gestureRuleSettingsAtom, { ...current, customRules: newRules });
});

/**
 * Remove a custom gesture rule by ID.
 */
export const removeGestureRuleAtom = atom(null, (get, set, ruleId: string) => {
	const current = get(gestureRuleSettingsAtom);
	set(gestureRuleSettingsAtom, {
		...current,
		customRules: current.customRules.filter((r) => r.id !== ruleId),
	});
});

/**
 * Update an existing custom gesture rule.
 */
export const updateGestureRuleAtom = atom(
	null,
	(get, set, { id, updates }: { id: string; updates: Partial<Omit<GestureRule, 'id'>> }) => {
		const current = get(gestureRuleSettingsAtom);
		const index = current.customRules.findIndex((r) => r.id === id);
		if (index < 0) return;

		const newRules = [...current.customRules];
		newRules[index] = { ...newRules[index], ...updates };

		set(gestureRuleSettingsAtom, { ...current, customRules: newRules });
	},
);

/**
 * Reset all custom rules (revert to defaults).
 */
export const resetGestureRulesAtom = atom(null, (get, set) => {
	const current = get(gestureRuleSettingsAtom);
	set(gestureRuleSettingsAtom, { ...current, customRules: [] });
});
