/**
 * useRegisterInputActions — Action registration hook
 *
 * Registers all built-in input actions (selection, clipboard, navigation,
 * commands, etc.) into the gesture dispatcher. Business logic lives in
 * ./input-action-helpers.ts for testability.
 */

import { useEffect } from 'react';
import { useStore } from 'jotai';
import {
	copyToClipboardAtom,
	duplicateSelectionAtom,
	fitToBoundsAtom,
	lockedNodeIdAtom,
	lockNodeAtom,
	mergeNodesAtom,
	pasteFromClipboardAtom,
	selectEdgeAtom,
	selectSingleNodeAtom,
	setFocusedNodeAtom,
	toggleNodeInSelectionAtom,
	unlockNodeAtom,
	undoAtom,
	redoAtom,
	centerOnNodeAtom,
	resetKeyboardInteractionModeAtom,
	resetInputModeAtom,
} from '../core';
import { openCommandLineAtom } from '../commands/store';
import { nextSearchResultAtom, prevSearchResultAtom } from '../core/search-store';
import { registerAction, unregisterAction } from './dispatcher';
import type { InputEvent } from './types';
import {
	isRepeatBlocked,
	getSelectedNodeIds,
	clearSelectionState,
	updateKeySubject,
	navigateFocus,
	cycleFocus,
	activateFocusedNode,
	nudgeSelection,
	deleteSelection,
	cutSelection,
	cancelActiveInteraction,
	escapeInput,
	resolvePickNode,
	finishPickNodes,
	resolvePickPoint,
	selectAll,
} from './input-action-helpers';

function register(actionId: string, handler: (event: InputEvent) => void): () => void {
	registerAction(actionId, handler);
	return () => unregisterAction(actionId);
}

export function useRegisterInputActions(): void {
	const store = useStore();

	useEffect(() => {
		const unregister = [
			// --- Selection ---
			register('select-node', (event) => {
				updateKeySubject(event, store);
				if (event.subject?.kind !== 'node') return;
				store.set(setFocusedNodeAtom, event.subject.nodeId);
				if (event.kind === 'key') {
					store.set(selectSingleNodeAtom, event.subject.nodeId);
				}
			}),
			register('select-edge', (event) => {
				updateKeySubject(event, store);
				if (event.subject?.kind !== 'edge') return;
				store.set(selectEdgeAtom, event.subject.edgeId);
			}),
			register('toggle-selection', (event) => {
				updateKeySubject(event, store);
				if (event.subject?.kind !== 'node') return;
				store.set(setFocusedNodeAtom, event.subject.nodeId);
				if (event.kind === 'key') {
					store.set(toggleNodeInSelectionAtom, event.subject.nodeId);
				}
			}),
			register('clear-selection', () => {
				clearSelectionState(store);
			}),
			register('select-all', (event) => {
				if (isRepeatBlocked(event)) return;
				selectAll(store);
			}),

			// --- Viewport ---
			register('fit-to-view', (event) => {
				updateKeySubject(event, store);
				if (event.subject?.kind === 'node') {
					store.set(centerOnNodeAtom, event.subject.nodeId);
				}
			}),
			register('fit-all-to-view', () => {
				store.set(fitToBoundsAtom, { mode: 'graph' });
			}),
			register('toggle-lock', (event) => {
				updateKeySubject(event, store);
				if (event.subject?.kind !== 'node') return;
				if (store.get(lockedNodeIdAtom) === event.subject.nodeId) {
					store.set(unlockNodeAtom);
				} else {
					store.set(lockNodeAtom, { nodeId: event.subject.nodeId });
				}
			}),

			// --- Commands & Search ---
			register('open-command-line', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(openCommandLineAtom);
			}),
			register('open-search', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(openCommandLineAtom);
			}),
			register('search-next-result', () => {
				store.set(nextSearchResultAtom);
			}),
			register('search-prev-result', () => {
				store.set(prevSearchResultAtom);
			}),

			// --- Clipboard ---
			register('copy-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				const selectedNodeIds = getSelectedNodeIds(store);
				if (selectedNodeIds.length > 0) {
					store.set(copyToClipboardAtom, selectedNodeIds);
				}
			}),
			register('cut-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				cutSelection(store);
			}),
			register('paste-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(pasteFromClipboardAtom);
			}),
			register('duplicate-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(duplicateSelectionAtom);
			}),
			register('merge-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				const nodeIds = getSelectedNodeIds(store);
				if (nodeIds.length >= 2) {
					store.set(mergeNodesAtom, { nodeIds });
				}
			}),
			register('delete-selection', (event) => {
				if (isRepeatBlocked(event)) return;
				deleteSelection(store);
			}),

			// --- History ---
			register('undo', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(undoAtom);
			}),
			register('redo', (event) => {
				if (isRepeatBlocked(event)) return;
				store.set(redoAtom);
			}),

			// --- Escape / Cancel ---
			register('cancel-active-input', () => {
				cancelActiveInteraction(store);
			}),
			register('escape-input', () => {
				escapeInput(store);
			}),

			// --- Keyboard Navigation ---
			register('navigate-focus-up', () => {
				navigateFocus(store, 'up');
			}),
			register('navigate-focus-down', () => {
				navigateFocus(store, 'down');
			}),
			register('navigate-focus-left', () => {
				navigateFocus(store, 'left');
			}),
			register('navigate-focus-right', () => {
				navigateFocus(store, 'right');
			}),
			register('cycle-focus-forward', (event) => {
				if (isRepeatBlocked(event)) return;
				cycleFocus(store, 1);
			}),
			register('cycle-focus-backward', (event) => {
				if (isRepeatBlocked(event)) return;
				cycleFocus(store, -1);
			}),
			register('activate-focused-node', (event) => {
				if (isRepeatBlocked(event)) return;
				activateFocusedNode(store, false);
			}),
			register('enter-keyboard-manipulate-mode', (event) => {
				if (isRepeatBlocked(event)) return;
				activateFocusedNode(store, true);
			}),
			register('exit-keyboard-manipulate-mode', () => {
				store.set(resetKeyboardInteractionModeAtom);
			}),

			// --- Nudge ---
			register('nudge-selection-up', () => {
				nudgeSelection(store, 0, -10, 'Nudge selection');
			}),
			register('nudge-selection-down', () => {
				nudgeSelection(store, 0, 10, 'Nudge selection');
			}),
			register('nudge-selection-left', () => {
				nudgeSelection(store, -10, 0, 'Nudge selection');
			}),
			register('nudge-selection-right', () => {
				nudgeSelection(store, 10, 0, 'Nudge selection');
			}),
			register('nudge-selection-up-large', () => {
				nudgeSelection(store, 0, -50, 'Nudge selection');
			}),
			register('nudge-selection-down-large', () => {
				nudgeSelection(store, 0, 50, 'Nudge selection');
			}),
			register('nudge-selection-left-large', () => {
				nudgeSelection(store, -50, 0, 'Nudge selection');
			}),
			register('nudge-selection-right-large', () => {
				nudgeSelection(store, 50, 0, 'Nudge selection');
			}),

			// --- Pick Mode ---
			register('resolve-pick-node', (event) => {
				resolvePickNode(event, store);
			}),
			register('finish-pick-nodes', () => {
				finishPickNodes(store);
			}),
			register('resolve-pick-point', (event) => {
				resolvePickPoint(event, store);
			}),
			register('cancel-pick', () => {
				store.set(resetInputModeAtom);
			}),
		];

		return () => {
			for (const cleanup of unregister) {
				cleanup();
			}
		};
	}, [store]);
}
