import { describe, it, expect } from 'vitest';
import { PanInertia, ZoomInertia, VelocitySampler } from '../inertia';

describe('PanInertia', () => {
	it('decays velocity each tick', () => {
		const inertia = new PanInertia({ x: 100, y: 0 }, 0.5, 1);
		const t1 = inertia.tick();
		expect(t1).not.toBeNull();
		expect(t1!.x).toBe(50);

		const t2 = inertia.tick();
		expect(t2).not.toBeNull();
		expect(t2!.x).toBe(25);
	});

	it('returns null when below threshold', () => {
		const inertia = new PanInertia({ x: 2, y: 0 }, 0.1, 1);
		const result = inertia.tick();
		// 2 * 0.1 = 0.2, below 1
		expect(result).toBeNull();
	});

	it('handles both axes', () => {
		const inertia = new PanInertia({ x: 10, y: 20 }, 0.5, 1);
		const t = inertia.tick();
		expect(t).toEqual({ x: 5, y: 10 });
	});
});

describe('ZoomInertia', () => {
	it('decays velocity each tick', () => {
		const inertia = new ZoomInertia(1.0, { x: 400, y: 300 }, 0.5, 0.01);
		const result = inertia.tick(1.5);
		expect(result).not.toBeNull();
		expect(result!.delta).toBe(0.5);
		expect(result!.origin).toEqual({ x: 400, y: 300 });
	});

	it('returns null when below threshold', () => {
		const inertia = new ZoomInertia(0.001, { x: 0, y: 0 }, 0.5, 0.01);
		const result = inertia.tick(1.5);
		// 0.001 * 0.5 = 0.0005, below 0.01
		expect(result).toBeNull();
	});

	it('snaps to 100% when close', () => {
		const inertia = new ZoomInertia(0.001, { x: 0, y: 0 }, 0.5, 0.01, 0.05);
		// velocity below threshold, zoom close to 1
		const result = inertia.tick(0.98);
		expect(result).not.toBeNull();
		expect(result!.delta).toBeCloseTo(0.02, 5);
	});
});

describe('VelocitySampler', () => {
	it('averages samples correctly', () => {
		const sampler = new VelocitySampler(5);
		sampler.sample(10, 20, 0);
		sampler.sample(20, 40, 1);
		const avg = sampler.average();
		expect(avg.x).toBe(15);
		expect(avg.y).toBe(30);
	});

	it('evicts oldest when full', () => {
		const sampler = new VelocitySampler(2);
		sampler.sample(10, 0, 0);
		sampler.sample(20, 0, 1);
		sampler.sample(30, 0, 2); // evicts 10
		const avg = sampler.average();
		expect(avg.x).toBe(25); // (20 + 30) / 2
	});

	it('returns zero for empty sampler', () => {
		const sampler = new VelocitySampler();
		expect(sampler.average()).toEqual({ x: 0, y: 0 });
	});

	it('reset clears samples', () => {
		const sampler = new VelocitySampler();
		sampler.sample(100, 100, 0);
		sampler.reset();
		expect(sampler.average()).toEqual({ x: 0, y: 0 });
	});
});
