/**
 * Gesture Rules — Defaults, Labels & Merge
 *
 * Default gesture rule definitions and merge utilities.
 * Split from gesture-rules.ts for modularity.
 */

import type {
	InputSource,
	GestureType,
	GestureTarget,
	GestureButton,
	ModifierFlags,
	GesturePattern,
	GestureRule,
} from './gesture-rules-types';

// =============================================================================
// Label Generation
// =============================================================================

const MODIFIER_KEYS: (keyof ModifierFlags)[] = ['shift', 'ctrl', 'alt', 'meta'];

const SOURCE_LABELS: Record<InputSource, string> = {
	mouse: 'Mouse',
	pencil: 'Pencil',
	finger: 'Touch',
};

const GESTURE_LABELS: Record<GestureType, string> = {
	tap: 'Tap',
	'double-tap': 'Double-tap',
	'triple-tap': 'Triple-tap',
	drag: 'Drag',
	'long-press': 'Long-press',
	'right-click': 'Right-click',
	pinch: 'Pinch',
	scroll: 'Scroll',
};

const TARGET_LABELS: Record<GestureTarget, string> = {
	node: 'node',
	edge: 'edge',
	port: 'port',
	'resize-handle': 'resize handle',
	background: 'background',
};

const BUTTON_LABELS: Record<GestureButton, string> = {
	0: 'Left',
	1: 'Middle',
	2: 'Right',
};

/**
 * Generate a human-readable label from a gesture pattern.
 */
export function formatRuleLabel(pattern: GesturePattern): string {
	const parts: string[] = [];

	// Modifiers first
	if (pattern.modifiers) {
		const mods = MODIFIER_KEYS
			.filter((k) => pattern.modifiers![k])
			.map((k) => k.charAt(0).toUpperCase() + k.slice(1));
		if (mods.length) parts.push(mods.join('+'));
	}

	// Button (only for non-left)
	if (pattern.button !== undefined && pattern.button !== 0) {
		parts.push(BUTTON_LABELS[pattern.button]);
	}

	// Source
	if (pattern.source) {
		parts.push(SOURCE_LABELS[pattern.source]);
	}

	// Gesture
	if (pattern.gesture) {
		parts.push(GESTURE_LABELS[pattern.gesture] ?? pattern.gesture);
	}

	// Target
	if (pattern.target) {
		parts.push('on ' + (TARGET_LABELS[pattern.target] ?? pattern.target));
	}

	if (parts.length === 0) return 'Any gesture';

	// Join with spaces, but use " + " before gesture if modifiers present
	if (pattern.modifiers) {
		const modCount = MODIFIER_KEYS.filter((k) => pattern.modifiers![k]).length;
		if (modCount > 0 && parts.length > modCount) {
			const modPart = parts.slice(0, 1).join('');
			const rest = parts.slice(1).join(' ').toLowerCase();
			return `${modPart} + ${rest}`;
		}
	}

	return parts.join(' ');
}

// =============================================================================
// Merge Utilities
// =============================================================================

/**
 * Merge consumer-provided rules with defaults.
 * Consumer rules override defaults with the same ID.
 * Consumer rules without matching IDs are appended.
 */
export function mergeRules(defaults: readonly GestureRule[], overrides: readonly GestureRule[]): GestureRule[] {
	const overrideMap = new Map(overrides.map((r) => [r.id, r]));
	const result: GestureRule[] = [];

	// Apply overrides to matching defaults
	for (const rule of defaults) {
		const override = overrideMap.get(rule.id);
		if (override) {
			result.push(override);
			overrideMap.delete(rule.id);
		} else {
			result.push(rule);
		}
	}

	// Append remaining overrides (new rules)
	for (const rule of overrideMap.values()) {
		result.push(rule);
	}

	return result;
}

// =============================================================================
// Default Rules
// =============================================================================

/**
 * Default gesture rules that replicate the current canvas behavior.
 */
export const DEFAULT_GESTURE_RULES: GestureRule[] = [
	// ── Tap gestures ──────────────────────────────────────────────
	{ id: 'tap-node', pattern: { gesture: 'tap', target: 'node' }, actionId: 'select-node' },
	{ id: 'tap-edge', pattern: { gesture: 'tap', target: 'edge' }, actionId: 'select-edge' },
	{ id: 'tap-port', pattern: { gesture: 'tap', target: 'port' }, actionId: 'select-node' },
	{ id: 'tap-bg', pattern: { gesture: 'tap', target: 'background' }, actionId: 'clear-selection' },

	// ── Double-tap ────────────────────────────────────────────────
	{ id: 'dtap-node', pattern: { gesture: 'double-tap', target: 'node' }, actionId: 'fit-to-view' },
	{ id: 'dtap-bg', pattern: { gesture: 'double-tap', target: 'background' }, actionId: 'fit-all-to-view' },

	// ── Triple-tap ────────────────────────────────────────────────
	{ id: 'ttap-node', pattern: { gesture: 'triple-tap', target: 'node' }, actionId: 'toggle-lock' },

	// ── Left-button drag ──────────────────────────────────────────
	{ id: 'drag-node', pattern: { gesture: 'drag', target: 'node' }, actionId: 'move-node' },
	{ id: 'drag-port', pattern: { gesture: 'drag', target: 'port' }, actionId: 'create-edge' },
	{ id: 'drag-bg-finger', pattern: { gesture: 'drag', target: 'background', source: 'finger' }, actionId: 'pan' },
	{ id: 'drag-bg-mouse', pattern: { gesture: 'drag', target: 'background', source: 'mouse' }, actionId: 'pan' },
	{ id: 'drag-bg-pencil', pattern: { gesture: 'drag', target: 'background', source: 'pencil' }, actionId: 'lasso-select' },

	// ── Shift+drag overrides ──────────────────────────────────────
	{ id: 'shift-drag-bg', pattern: { gesture: 'drag', target: 'background', modifiers: { shift: true } }, actionId: 'rect-select' },

	// ── Right-click tap (context menu) ────────────────────────────
	{ id: 'rc-node', pattern: { gesture: 'tap', target: 'node', button: 2 }, actionId: 'open-context-menu' },
	{ id: 'rc-edge', pattern: { gesture: 'tap', target: 'edge', button: 2 }, actionId: 'open-context-menu' },
	{ id: 'rc-bg', pattern: { gesture: 'tap', target: 'background', button: 2 }, actionId: 'open-context-menu' },

	// ── Long-press ────────────────────────────────────────────────
	{ id: 'lp-node', pattern: { gesture: 'long-press', target: 'node' }, actionId: 'open-context-menu' },
	{ id: 'lp-bg-finger', pattern: { gesture: 'long-press', target: 'background', source: 'finger' }, actionId: 'create-node' },

	// ── Right-button drag (defaults to none — consumers override) ─
	{ id: 'rdrag-node', pattern: { gesture: 'drag', target: 'node', button: 2 }, actionId: 'none' },
	{ id: 'rdrag-bg', pattern: { gesture: 'drag', target: 'background', button: 2 }, actionId: 'none' },

	// ── Middle-button drag (defaults to none) ─────────────────────
	{ id: 'mdrag-node', pattern: { gesture: 'drag', target: 'node', button: 1 }, actionId: 'none' },
	{ id: 'mdrag-bg', pattern: { gesture: 'drag', target: 'background', button: 1 }, actionId: 'none' },

	// ── Zoom ──────────────────────────────────────────────────────
	{ id: 'pinch-bg', pattern: { gesture: 'pinch', target: 'background' }, actionId: 'zoom' },
	{ id: 'scroll-any', pattern: { gesture: 'scroll' }, actionId: 'zoom' },

	// ── Split ─────────────────────────────────────────────────────
	{ id: 'pinch-node', pattern: { gesture: 'pinch', target: 'node' }, actionId: 'split-node' },
];
