import { describe, it, expect } from 'vitest';
import { buildMappingIndex, resolve } from '../mapper';
import { PALM_REJECTION_CONTEXT, DEFAULT_CONTEXT } from '../contexts';
import type { GestureEvent, GuardContext } from '../types';
import { NO_HELD_KEYS, NO_MODIFIERS } from '../types';

function makeEvent(overrides: Partial<GestureEvent> = {}): GestureEvent {
	return {
		type: 'tap',
		phase: 'instant',
		subject: { kind: 'node', nodeId: 'n1' },
		source: 'finger',
		button: 0,
		modifiers: NO_MODIFIERS,
		heldKeys: NO_HELD_KEYS,
		screenPosition: { x: 0, y: 0 },
		worldPosition: { x: 0, y: 0 },
		...overrides,
	};
}

function makeGuard(overrides: Partial<GuardContext> = {}): GuardContext {
	return {
		isStylusActive: false,
		fingerCount: 0,
		isDragging: false,
		isResizing: false,
		isSplitting: false,
		inputMode: { type: 'normal' },
		keyboardInteractionMode: 'navigate',
		selectedNodeIds: new Set(),
		focusedNodeId: null,
		isSearchActive: false,
		commandLineVisible: false,
		heldKeys: NO_HELD_KEYS,
		custom: {},
		...overrides,
	};
}

describe('palm rejection context', () => {
	const index = buildMappingIndex([PALM_REJECTION_CONTEXT, DEFAULT_CONTEXT]);

	it('finger tap resolves to select-node when stylus NOT active', () => {
		const result = resolve(makeEvent(), index, makeGuard());
		expect(result).not.toBeNull();
		expect(result!.actionId).toBe('select-node');
	});

	it('finger tap is consumed (none) when stylus IS active', () => {
		const result = resolve(makeEvent(), index, makeGuard({ isStylusActive: true }));
		expect(result).not.toBeNull();
		expect(result!.actionId).toBe('none');
		expect(result!.consumed).toBe(true);
	});

	it('finger double-tap is consumed when stylus active', () => {
		const event = makeEvent({ type: 'double-tap' });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result!.actionId).toBe('none');
	});

	it('finger long-press is consumed when stylus active', () => {
		const event = makeEvent({ type: 'long-press' });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result!.actionId).toBe('none');
	});

	it('finger drag on node becomes pan when stylus active', () => {
		const event = makeEvent({ type: 'drag', phase: 'start' });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result!.actionId).toBe('pan');
	});

	it('pencil tap still works when stylus active', () => {
		const event = makeEvent({ source: 'pencil' });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result!.actionId).toBe('select-node');
	});

	it('pinch is NOT blocked by palm rejection (no finger-pinch binding)', () => {
		const event = makeEvent({ type: 'pinch', subject: { kind: 'background' } });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result).not.toBeNull();
		expect(result!.actionId).toBe('zoom');
	});

	it('scroll is NOT blocked by palm rejection', () => {
		const event = makeEvent({ type: 'scroll', source: 'mouse', subject: { kind: 'background' } });
		const result = resolve(event, index, makeGuard({ isStylusActive: true }));
		expect(result).not.toBeNull();
		expect(result!.actionId).toBe('zoom');
	});
});
