/**
 * Gesture System v2 — Core Types
 *
 * Single source of truth for every type in the gesture pipeline.
 * No runtime code — pure type definitions.
 */

import type { InputSource } from '../core/input-classifier';
import type { InputMode, KeyboardInteractionMode } from '../core/interaction-store';

// =============================================================================
// Layer 1: Normalize
// =============================================================================

export type PointerLifecycle = 'down' | 'move' | 'up' | 'cancel';

export type Button = 0 | 1 | 2;

export interface Modifiers {
	shift: boolean;
	ctrl: boolean;
	alt: boolean;
	meta: boolean;
	/** Non-keyboard modifier flags (touch toolbars, stylus buttons, etc.). */
	custom?: Record<string, boolean>;
}

export const NO_MODIFIERS: Modifiers = Object.freeze({
	shift: false,
	ctrl: false,
	alt: false,
	meta: false,
});

export interface HeldKeysState {
	byKey: Readonly<Record<string, boolean>>;
	byCode: Readonly<Record<string, boolean>>;
}

export const NO_HELD_KEYS: HeldKeysState = Object.freeze({
	byKey: Object.freeze({}),
	byCode: Object.freeze({}),
});

export interface NormalizedPointer {
	pointerId: number;
	lifecycle: PointerLifecycle;
	source: InputSource;
	button: Button;
	modifiers: Modifiers;
	screenX: number;
	screenY: number;
	pressure: number;
	timestamp: number;
}

// =============================================================================
// Layer 2: Recognize
// =============================================================================

export type PointerGestureType =
	| 'tap'
	| 'double-tap'
	| 'triple-tap'
	| 'long-press'
	| 'drag'
	| 'pinch'
	| 'scroll';

export type GestureType = PointerGestureType;

export type PointerGesturePhase = 'start' | 'move' | 'end' | 'instant' | 'cancel';
export type KeyInputPhase = 'down' | 'up';
export type InputPhase = PointerGesturePhase | KeyInputPhase;

export type GestureSubject =
	| { kind: 'background' }
	| { kind: 'node'; nodeId: string }
	| { kind: 'edge'; edgeId: string }
	| { kind: 'port'; nodeId: string; portId: string };

export type SubjectKind = GestureSubject['kind'];

export interface Vec2 {
	x: number;
	y: number;
}

export interface PointerGestureEvent {
	kind?: 'pointer';
	type: PointerGestureType;
	phase: PointerGesturePhase;
	subject: GestureSubject;
	source: InputSource;
	button: Button;
	modifiers: Modifiers;
	heldKeys: HeldKeysState;
	pointerId?: number;
	screenPosition: Vec2;
	worldPosition: Vec2;
	delta?: Vec2;
	velocity?: Vec2;
	scale?: number;
	originalEvent?: Event;
}

export interface KeyInputEvent {
	kind: 'key';
	phase: KeyInputPhase;
	key: string;
	code: string;
	repeat: boolean;
	modifiers: Modifiers;
	heldKeys: HeldKeysState;
	subject?: GestureSubject;
	screenPosition?: Vec2;
	worldPosition?: Vec2;
	originalEvent?: Event;
}

export type InputEvent = PointerGestureEvent | KeyInputEvent;
export type GestureEvent = PointerGestureEvent;

// =============================================================================
// Layer 2: Timed State
// =============================================================================

export type TimedStateTag = 'idle' | 'pressed' | 'released' | 'long-pressed';

export interface TimedState {
	tag: TimedStateTag;
	tapCount: number;
}

export interface TimedStateResult {
	state: TimedState;
	emit?: PointerGestureType;
	scheduleTimer?: { id: string; delayMs: number };
	cancelTimer?: string;
}

// =============================================================================
// Layer 3: Resolve
// =============================================================================

export interface HeldKeysPattern {
	byKey?: Record<string, boolean>;
	byCode?: Record<string, boolean>;
}

export interface InputPattern {
	kind?: 'pointer' | 'key';
	type?: PointerGestureType;
	subjectKind?: SubjectKind;
	source?: InputSource;
	button?: Button;
	phase?: InputPhase;
	modifiers?: Partial<Modifiers>;
	key?: string;
	code?: string;
	heldKeys?: HeldKeysPattern;
}

export type GesturePattern = InputPattern;

export interface Binding {
	id: string;
	pattern: InputPattern;
	actionId: string;
	consumeInput?: boolean;
	when?: (ctx: GuardContext) => boolean;
}

export interface MappingContext {
	id: string;
	priority: number;
	enabled: boolean;
	bindings: Binding[];
}

export interface GuardContext {
	isStylusActive: boolean;
	fingerCount: number;
	isDragging: boolean;
	isResizing: boolean;
	isSplitting: boolean;
	inputMode: InputMode;
	keyboardInteractionMode: KeyboardInteractionMode;
	selectedNodeIds: ReadonlySet<string>;
	focusedNodeId: string | null;
	isSearchActive: boolean;
	commandLineVisible: boolean;
	heldKeys: HeldKeysState;
	custom: Record<string, unknown>;
}

export interface ResolvedAction {
	actionId: string;
	binding: Binding;
	contextId: string;
	score: number;
	consumed: boolean;
}

// =============================================================================
// Layer 4: Dispatch
// =============================================================================

export type BivariantCallback<Args extends unknown[], Result = void> = {
	bivarianceHack: (...args: Args) => Result;
}['bivarianceHack'];

export interface PhaseHandler {
	onStart?: BivariantCallback<[PointerGestureEvent]>;
	onMove?: BivariantCallback<[PointerGestureEvent]>;
	onEnd?: BivariantCallback<[PointerGestureEvent]>;
	onInstant?: BivariantCallback<[PointerGestureEvent]>;
	onCancel?: BivariantCallback<[PointerGestureEvent]>;
	onDown?: BivariantCallback<[KeyInputEvent]>;
	onUp?: BivariantCallback<[KeyInputEvent]>;
}

/**
 * Action handler. Simple function form fires only on 'start' and 'instant'.
 * Object form routes each phase to a dedicated method.
 */
export type ActionHandler = BivariantCallback<[InputEvent]> | PhaseHandler;

export function isKeyInputEvent(event: InputEvent): event is KeyInputEvent {
	return event.kind === 'key';
}

export function isPointerGestureEvent(event: InputEvent): event is PointerGestureEvent {
	return event.kind !== 'key';
}

// =============================================================================
// Re-exports for convenience
// =============================================================================

export type { InputSource } from '../core/input-classifier';
export type { InputMode, KeyboardInteractionMode } from '../core/interaction-store';
