import { describe, it, expect, beforeEach } from 'vitest';
import { createStore } from 'jotai';
import {
	snapEnabledAtom,
	snapGridSizeAtom,
	snapTemporaryDisableAtom,
	isSnappingActiveAtom,
	snapToGrid,
	conditionalSnap,
	getSnapGuides,
	toggleSnapAtom,
	setGridSizeAtom,
	snapAlignmentEnabledAtom,
	toggleAlignmentGuidesAtom,
	alignmentGuidesAtom,
	clearAlignmentGuidesAtom,
} from '../core/snap-store';

describe('snap-store', () => {
	let store: ReturnType<typeof createStore>;

	beforeEach(() => {
		store = createStore();
	});

	describe('initial state', () => {
		it('snap disabled by default', () => {
			expect(store.get(snapEnabledAtom)).toBe(false);
		});

		it('grid size defaults to 20', () => {
			expect(store.get(snapGridSizeAtom)).toBe(20);
		});

		it('alignment guides enabled by default', () => {
			expect(store.get(snapAlignmentEnabledAtom)).toBe(true);
		});
	});

	describe('isSnappingActiveAtom', () => {
		it('false when disabled', () => {
			expect(store.get(isSnappingActiveAtom)).toBe(false);
		});

		it('true when enabled and not temporarily disabled', () => {
			store.set(snapEnabledAtom, true);
			expect(store.get(isSnappingActiveAtom)).toBe(true);
		});

		it('false when enabled but temporarily disabled', () => {
			store.set(snapEnabledAtom, true);
			store.set(snapTemporaryDisableAtom, true);
			expect(store.get(isSnappingActiveAtom)).toBe(false);
		});
	});

	describe('toggleSnapAtom', () => {
		it('toggles snap on', () => {
			store.set(toggleSnapAtom);
			expect(store.get(snapEnabledAtom)).toBe(true);
		});

		it('toggles snap off', () => {
			store.set(snapEnabledAtom, true);
			store.set(toggleSnapAtom);
			expect(store.get(snapEnabledAtom)).toBe(false);
		});
	});

	describe('setGridSizeAtom', () => {
		it('sets grid size', () => {
			store.set(setGridSizeAtom, 50);
			expect(store.get(snapGridSizeAtom)).toBe(50);
		});

		it('clamps minimum to 5', () => {
			store.set(setGridSizeAtom, 1);
			expect(store.get(snapGridSizeAtom)).toBe(5);
		});

		it('clamps maximum to 200', () => {
			store.set(setGridSizeAtom, 999);
			expect(store.get(snapGridSizeAtom)).toBe(200);
		});
	});

	describe('toggleAlignmentGuidesAtom', () => {
		it('toggles off', () => {
			store.set(toggleAlignmentGuidesAtom);
			expect(store.get(snapAlignmentEnabledAtom)).toBe(false);
		});
	});

	describe('alignmentGuidesAtom', () => {
		it('starts empty', () => {
			const guides = store.get(alignmentGuidesAtom);
			expect(guides.verticalGuides).toEqual([]);
			expect(guides.horizontalGuides).toEqual([]);
		});

		it('can be set and cleared', () => {
			store.set(alignmentGuidesAtom, { verticalGuides: [100], horizontalGuides: [200] });
			expect(store.get(alignmentGuidesAtom).verticalGuides).toEqual([100]);

			store.set(clearAlignmentGuidesAtom);
			expect(store.get(alignmentGuidesAtom).verticalGuides).toEqual([]);
		});
	});
});

describe('snap pure functions', () => {
	describe('snapToGrid', () => {
		it('snaps to nearest grid point', () => {
			expect(snapToGrid({ x: 17, y: 33 }, 20)).toEqual({ x: 20, y: 40 });
		});

		it('stays at grid point if already aligned', () => {
			expect(snapToGrid({ x: 40, y: 60 }, 20)).toEqual({ x: 40, y: 60 });
		});
	});

	describe('conditionalSnap', () => {
		it('snaps when active', () => {
			expect(conditionalSnap({ x: 17, y: 33 }, 20, true)).toEqual({ x: 20, y: 40 });
		});

		it('returns original when inactive', () => {
			expect(conditionalSnap({ x: 17, y: 33 }, 20, false)).toEqual({ x: 17, y: 33 });
		});
	});

	describe('getSnapGuides', () => {
		it('returns guide positions within tolerance', () => {
			const guides = getSnapGuides({ x: 19, y: 41 }, 20, 5);
			expect(guides.x).toBe(20);
			expect(guides.y).toBe(40);
		});

		it('returns null outside tolerance', () => {
			const guides = getSnapGuides({ x: 12, y: 30 }, 20, 2);
			expect(guides.x).toBeNull();
			expect(guides.y).toBeNull();
		});
	});
});
