import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { TimedStateRunner } from '../gestures/timed-state-runner';

describe('TimedStateRunner', () => {
	let runner: TimedStateRunner;

	beforeEach(() => {
		vi.useFakeTimers();
		runner = new TimedStateRunner();
	});

	afterEach(() => {
		runner.destroy();
		vi.useRealTimers();
	});

	it('starts in idle state', () => {
		expect(runner.tag).toBe('idle');
	});

	it('feed(down) transitions to pressed', () => {
		runner.feed('down');
		expect(runner.tag).toBe('pressed');
	});

	it('feed(down) then feed(up) emits tap', () => {
		runner.feed('down');
		const gesture = runner.feed('up');
		expect(gesture).toBe('tap');
	});

	it('feed(down) then feed(move-beyond-threshold) transitions out of pressed', () => {
		runner.feed('down');
		runner.feed('move-beyond-threshold');
		expect(runner.tag).not.toBe('pressed');
	});

	it('feed(cancel) returns to idle', () => {
		runner.feed('down');
		runner.feed('cancel');
		expect(runner.tag).toBe('idle');
	});

	it('destroy clears timers and resets state', () => {
		runner.feed('down');
		runner.destroy();
		expect(runner.tag).toBe('idle');
	});

	it('onEmit callback is called for long-press', () => {
		const emitted: string[] = [];
		runner.onEmit = (type) => emitted.push(type);

		runner.feed('down');
		vi.advanceTimersByTime(600);

		expect(emitted).toContain('long-press');
	});

	it('double-tap is detected', () => {
		runner.feed('down');
		runner.feed('up'); // first tap
		runner.feed('down');
		const gesture = runner.feed('up');
		expect(gesture).toBe('double-tap');
	});
});
