import { describe, expect, it } from 'vitest';

import {
	applyMotionStateMachine,
	computeChangedPixelRatio,
	computeLuma,
	createMotionMachineSnapshot
} from './motion-detector';

describe('motion-detector helpers', () => {
	it('computes grayscale luminance for RGBA image data', () => {
		const luminance = computeLuma({
			data: new Uint8ClampedArray([
				255, 0, 0, 255,
				0, 255, 0, 255
			])
		});

		expect(luminance).toHaveLength(2);
		expect(luminance[0]).toBeCloseTo(76.245, 3);
		expect(luminance[1]).toBeCloseTo(149.685, 3);
	});

	it('reports the ratio of changed pixels above the delta threshold', () => {
		const previousFrame = new Float32Array([0, 10, 20, 30]);
		const currentFrame = new Float32Array([0, 40, 20, 60]);

		expect(computeChangedPixelRatio(previousFrame, currentFrame, 18)).toBeCloseTo(0.5, 5);
		expect(computeChangedPixelRatio(previousFrame, currentFrame, 40)).toBe(0);
	});
});

describe('motion-detector state machine', () => {
	const config = {
		triggerThreshold: 0.12,
		releaseThreshold: 0.04,
		consecutiveTriggerFrames: 3,
		minimumEventMs: 8000,
		cooldownMs: 2000
	};

	it('requires consecutive high-motion frames before triggering', () => {
		let snapshot = createMotionMachineSnapshot();

		let result = applyMotionStateMachine(snapshot, { state: 'monitoring', score: 0.2 }, config, 1000);
		snapshot = result.snapshot;
		expect(result.output.state).toBe('candidate_motion');
		expect(result.output.activeMotion).toBe(false);

		result = applyMotionStateMachine(snapshot, { state: 'monitoring', score: 0.2 }, config, 1300);
		snapshot = result.snapshot;
		expect(result.output.state).toBe('candidate_motion');
		expect(result.output.activeMotion).toBe(false);

		result = applyMotionStateMachine(snapshot, { state: 'monitoring', score: 0.2 }, config, 1600);
		expect(result.output.state).toBe('triggered');
		expect(result.output.activeMotion).toBe(true);
		expect(result.snapshot.activeSince).toBe(1600);
	});

	it('holds motion until minimum duration and quiet cooldown complete', () => {
		let snapshot = createMotionMachineSnapshot({
			activeMotion: true,
			activeSince: 1000
		});

		let result = applyMotionStateMachine(snapshot, { state: 'monitoring', score: 0.01 }, config, 4000);
		snapshot = result.snapshot;
		expect(result.output.state).toBe('triggered');
		expect(result.snapshot.quietSince).toBe(4000);
		expect(result.output.activeMotion).toBe(true);

		result = applyMotionStateMachine(snapshot, { state: 'monitoring', score: 0.01 }, config, 9500);
		expect(result.output.state).toBe('cooldown');
		expect(result.output.activeMotion).toBe(false);
		expect(result.snapshot.activeSince).toBeNull();
		expect(result.snapshot.quietSince).toBeNull();
	});
});
