/**
 * Command Store — Action Atoms
 *
 * Action atoms and helper functions for managing the command line.
 * Core state atoms are in ./store-atoms.ts.
 */

import { atom } from 'jotai';
import type {
	CommandDefinition,
	InputDefinition,
	InputMode,
	FeedbackState,
	UINodeState,
} from './types';
import { commandRegistry } from './registry';

// Re-export all state atoms for backward compat
export {
	inputModeAtom,
	commandLineVisibleAtom,
	commandLineStateAtom,
	commandFeedbackAtom,
	commandHistoryAtom,
	selectedSuggestionIndexAtom,
	pendingInputResolverAtom,
	isCommandActiveAtom,
	currentInputAtom,
	commandProgressAtom,
} from './store-atoms';

// Import for internal use
import {
	inputModeAtom,
	commandLineVisibleAtom,
	commandLineStateAtom,
	commandFeedbackAtom,
	commandHistoryAtom,
	selectedSuggestionIndexAtom,
	pendingInputResolverAtom,
} from './store-atoms';

// =============================================================================
// Action Atoms
// =============================================================================

/**
 * Open the command line and enter search mode.
 */
export const openCommandLineAtom = atom(null, (get, set) => {
	set(commandLineVisibleAtom, true);
	set(commandLineStateAtom, { phase: 'searching', query: '', suggestions: commandRegistry.all() });
	set(selectedSuggestionIndexAtom, 0);
});

/**
 * Close the command line and reset state.
 */
export const closeCommandLineAtom = atom(null, (get, set) => {
	set(commandLineVisibleAtom, false);
	set(commandLineStateAtom, { phase: 'idle' });
	set(inputModeAtom, { type: 'normal' });
	set(commandFeedbackAtom, null);
	set(pendingInputResolverAtom, null);
});

/**
 * Update search query and suggestions.
 */
export const updateSearchQueryAtom = atom(null, (get, set, query: string) => {
	const suggestions = commandRegistry.search(query);
	set(commandLineStateAtom, { phase: 'searching', query, suggestions });
	set(selectedSuggestionIndexAtom, 0); // Reset selection on query change
});

/**
 * Select a command and start collecting inputs.
 */
export const selectCommandAtom = atom(null, (get, set, command: CommandDefinition) => {
	// Add to history
	const history = get(commandHistoryAtom);
	const newHistory = [command.name, ...history.filter((h) => h !== command.name)].slice(0, 50);
	set(commandHistoryAtom, newHistory);

	// If command has no inputs, execute immediately
	if (command.inputs.length === 0) {
		set(commandLineStateAtom, { phase: 'executing', command });
		return;
	}

	// Start collecting inputs
	set(commandLineStateAtom, {
		phase: 'collecting',
		command,
		inputIndex: 0,
		collected: {},
	});

	// Set input mode for first input
	const firstInput = command.inputs[0];
	set(inputModeAtom, inputDefToMode(firstInput));
});

/**
 * Provide a value for the current input and advance to next.
 */
export const provideInputAtom = atom(null, (get, set, value: unknown) => {
	const state = get(commandLineStateAtom);
	if (state.phase !== 'collecting') return;

	const { command, inputIndex, collected } = state;
	const currentInput = command.inputs[inputIndex];

	// Validate if validator exists
	if (currentInput.validate) {
		const result = currentInput.validate(value, collected);
		if (result !== true) {
			set(commandLineStateAtom, {
				phase: 'error',
				message: typeof result === 'string' ? result : `Invalid value for ${currentInput.name}`,
			});
			return;
		}
	}

	// Add to collected inputs
	const newCollected = { ...collected, [currentInput.name]: value };

	// Check if there are more inputs
	if (inputIndex < command.inputs.length - 1) {
		const nextInputIndex = inputIndex + 1;
		const nextInput = command.inputs[nextInputIndex];

		set(commandLineStateAtom, {
			phase: 'collecting',
			command,
			inputIndex: nextInputIndex,
			collected: newCollected,
		});

		// Set input mode for next input
		set(inputModeAtom, inputDefToMode(nextInput, newCollected));

		// Update feedback
		if (command.feedback) {
			const feedback = command.feedback(newCollected, nextInput);
			if (feedback) {
				// Convert CommandFeedback to FeedbackState
				const feedbackState: FeedbackState = {
					hoveredNodeId: feedback.highlightNodeId,
					ghostNode: feedback.ghostNode,
					crosshair: feedback.crosshair,
					// Handle previewEdge conversion - toCursor variant needs cursorWorldPos
					previewEdge:
						feedback.previewEdge && 'to' in feedback.previewEdge
							? { from: feedback.previewEdge.from, to: feedback.previewEdge.to }
							: undefined,
				};
				set(commandFeedbackAtom, feedbackState);
			} else {
				set(commandFeedbackAtom, null);
			}
		}
	} else {
		// All inputs collected, ready to execute
		set(commandLineStateAtom, {
			phase: 'collecting',
			command,
			inputIndex: inputIndex,
			collected: newCollected,
		});

		// Signal that we're ready to execute (the executor will handle this)
		set(inputModeAtom, { type: 'normal' });
	}
});

/**
 * Skip the current optional input and use default value.
 */
export const skipInputAtom = atom(null, (get, set) => {
	const state = get(commandLineStateAtom);
	if (state.phase !== 'collecting') return;

	const { command, inputIndex } = state;
	const currentInput = command.inputs[inputIndex];

	// Can only skip optional inputs
	if (currentInput.required !== false) {
		return;
	}

	// Use default value
	const value = currentInput.default;
	set(provideInputAtom, value);
});

/**
 * Go back to the previous input.
 */
export const goBackInputAtom = atom(null, (get, set) => {
	const state = get(commandLineStateAtom);
	if (state.phase !== 'collecting') return;

	const { command, inputIndex, collected } = state;

	if (inputIndex === 0) {
		// Go back to search
		set(commandLineStateAtom, {
			phase: 'searching',
			query: command.name,
			suggestions: [command],
		});
		set(inputModeAtom, { type: 'normal' });
		return;
	}

	// Go to previous input
	const prevInputIndex = inputIndex - 1;
	const prevInput = command.inputs[prevInputIndex];

	// Remove the previous value from collected
	const newCollected = { ...collected };
	delete newCollected[prevInput.name];

	set(commandLineStateAtom, {
		phase: 'collecting',
		command,
		inputIndex: prevInputIndex,
		collected: newCollected,
	});

	set(inputModeAtom, inputDefToMode(prevInput, newCollected));
});

/**
 * Set error state.
 */
export const setCommandErrorAtom = atom(null, (get, set, message: string) => {
	set(commandLineStateAtom, { phase: 'error', message });
	set(inputModeAtom, { type: 'normal' });
});

/**
 * Clear error and go back to idle.
 */
export const clearCommandErrorAtom = atom(null, (get, set) => {
	set(commandLineStateAtom, { phase: 'idle' });
});

// =============================================================================
// Helper Functions
// =============================================================================

/**
 * Convert an InputDefinition to an InputMode.
 */
function inputDefToMode(input: InputDefinition, collected?: Record<string, unknown>): InputMode {
	switch (input.type) {
		case 'point':
			return { type: 'pickPoint', prompt: input.prompt, snapToGrid: input.snapToGrid };
		case 'node':
			return {
				type: 'pickNode',
				prompt: input.prompt,
				filter: input.filter ? (node: UINodeState) => input.filter!(node, collected || {}) : undefined,
			};
		case 'nodes':
			return {
				type: 'pickNodes',
				prompt: input.prompt,
				filter: input.filter ? (node: UINodeState) => input.filter!(node, collected || {}) : undefined,
			};
		case 'select':
			return {
				type: 'select',
				prompt: input.prompt,
				options: input.options || [],
			};
		case 'text':
		case 'number':
		case 'color':
		case 'boolean':
		default:
			return { type: 'text', prompt: input.prompt };
	}
}
