import { describe, it, expect } from 'vitest';
import { transition, IDLE, DEFAULT_LONG_PRESS_MS, DEFAULT_MULTI_TAP_WINDOW_MS, LONG_PRESS_TIMER, SETTLE_TIMER } from '../gestures/timed-state';

describe('timed-state machine', () => {
	describe('transition from idle', () => {
		it('idle + down → pressed', () => {
			const result = transition(IDLE, 'down');
			expect(result.state.tag).toBe('pressed');
		});

		it('idle + down schedules long-press timer', () => {
			const result = transition(IDLE, 'down');
			expect(result.scheduleTimer?.id).toBe(LONG_PRESS_TIMER);
			expect(result.scheduleTimer?.delayMs).toBe(DEFAULT_LONG_PRESS_MS);
		});
	});

	describe('tap recognition', () => {
		it('pressed + up → released with tap emit', () => {
			const pressed = transition(IDLE, 'down').state;
			const result = transition(pressed, 'up');
			expect(result.state.tag).toBe('released');
			expect(result.emit).toBe('tap');
		});

		it('double-tap: pressed → released → pressed → released', () => {
			const s1 = transition(IDLE, 'down').state;     // pressed
			const s2 = transition(s1, 'up').state;          // released (tap 1)
			const s3 = transition(s2, 'down').state;        // pressed (tap 1 continuing)
			const result = transition(s3, 'up');             // released (tap 2)
			expect(result.emit).toBe('double-tap');
		});

		it('triple-tap after 3 down/up cycles', () => {
			let s = IDLE;
			for (let i = 0; i < 3; i++) {
				s = transition(s, 'down').state;
				const r = transition(s, 'up');
				s = r.state;
				if (i === 2) {
					expect(r.emit).toBe('triple-tap');
				}
			}
		});
	});

	describe('long-press', () => {
		it('pressed + long-press timer → long-pressed', () => {
			const pressed = transition(IDLE, 'down').state;
			const result = transition(pressed, 'timer:long-press');
			expect(result.state.tag).toBe('long-pressed');
			expect(result.emit).toBe('long-press');
		});

		it('long-pressed + up → idle', () => {
			const pressed = transition(IDLE, 'down').state;
			const longPressed = transition(pressed, 'timer:long-press').state;
			const result = transition(longPressed, 'up');
			expect(result.state.tag).toBe('idle');
		});
	});

	describe('drag escape', () => {
		it('pressed + move-beyond-threshold → idle (drag)', () => {
			const pressed = transition(IDLE, 'down').state;
			const result = transition(pressed, 'move-beyond-threshold');
			expect(result.state.tag).toBe('idle');
			expect(result.cancelTimer).toBe(LONG_PRESS_TIMER);
		});
	});

	describe('cancel', () => {
		it('cancel → idle', () => {
			const pressed = transition(IDLE, 'down').state;
			const result = transition(pressed, 'cancel');
			expect(result.state.tag).toBe('idle');
		});
	});

	describe('settle', () => {
		it('settle timer → idle', () => {
			const pressed = transition(IDLE, 'down').state;
			const released = transition(pressed, 'up').state;
			const result = transition(released, 'timer:settle');
			expect(result.state.tag).toBe('idle');
		});
	});
});
