import { describe, it, expect, vi } from 'vitest';
import { createPinchHandlers, type PinchZoomConfig } from '../gestures/usePinchZoom';
import { VelocitySampler } from '../gestures/inertia';

function makeConfig(overrides: Partial<PinchZoomConfig> = {}): PinchZoomConfig {
	const el = document.createElement('div');
	Object.defineProperty(el, 'getBoundingClientRect', {
		value: () => ({ left: 0, top: 0, width: 800, height: 600, right: 800, bottom: 600, x: 0, y: 0, toJSON: () => {} }),
	});

	return {
		ref: { current: el },
		minZoom: 0.1,
		maxZoom: 5,
		enableZoom: true,
		reducedMotion: false,
		zoom: 1,
		pan: { x: 0, y: 0 },
		setZoom: vi.fn() as any,
		setPan: vi.fn() as any,
		inertia: {
			cancelAll: vi.fn(),
			pinchPrevOrigin: { current: null },
			zoomSampler: new VelocitySampler(),
			lastPinchZoom: { current: null },
			startZoomInertia: vi.fn(),
		},
		...overrides,
	};
}

describe('createPinchHandlers', () => {
	it('returns onPinchStart, onPinch, onPinchEnd handlers', () => {
		const handlers = createPinchHandlers(makeConfig());
		expect(typeof handlers.onPinchStart).toBe('function');
		expect(typeof handlers.onPinch).toBe('function');
		expect(typeof handlers.onPinchEnd).toBe('function');
	});

	it('onPinchStart initializes tracking state', () => {
		const config = makeConfig();
		const { onPinchStart } = createPinchHandlers(config);

		const result = onPinchStart({ origin: [400, 300] });

		expect(result).toBe(false); // false = handled, don't skip
		expect(config.inertia.cancelAll).toHaveBeenCalled();
		expect(config.inertia.pinchPrevOrigin.current).toEqual({ x: 400, y: 300 });
	});

	it('onPinchStart returns true when zoom disabled', () => {
		const config = makeConfig({ enableZoom: false });
		const { onPinchStart } = createPinchHandlers(config);

		const result = onPinchStart({ origin: [400, 300] });

		expect(result).toBe(true); // true = skip
	});

	it('onPinch updates zoom and pan', () => {
		const config = makeConfig();
		config.inertia.pinchPrevOrigin.current = { x: 400, y: 300 };
		config.inertia.lastPinchZoom.current = { zoom: 1, t: performance.now() - 16 };
		const { onPinch } = createPinchHandlers(config);

		onPinch({
			offset: [1.5, 0],
			origin: [410, 310],
			event: { preventDefault: vi.fn() } as any,
			memo: undefined,
		});

		expect(config.setZoom).toHaveBeenCalled();
		expect(config.setPan).toHaveBeenCalled();
	});

	it('onPinchEnd resets tracking state', () => {
		const config = makeConfig();
		config.inertia.pinchPrevOrigin.current = { x: 400, y: 300 };
		config.inertia.lastPinchZoom.current = { zoom: 1, t: performance.now() };
		const { onPinchEnd } = createPinchHandlers(config);

		onPinchEnd();

		expect(config.inertia.pinchPrevOrigin.current).toBeNull();
		expect(config.inertia.lastPinchZoom.current).toBeNull();
	});
});
