import { describe, it, expect, beforeEach } from 'vitest';
import { createStore } from 'jotai';
import {
	gestureRuleSettingsAtom,
	consumerGestureRulesAtom,
	gestureRulesAtom,
	gestureRuleIndexAtom,
	palmRejectionEnabledAtom,
	addGestureRuleAtom,
	removeGestureRuleAtom,
	updateGestureRuleAtom,
	resetGestureRulesAtom,
} from '../core/gesture-rule-store';
import type { GestureRule } from '../core/gesture-rules';

function freshStore() {
	const store = createStore();
	store.set(gestureRuleSettingsAtom, { customRules: [], palmRejection: true });
	store.set(consumerGestureRulesAtom, []);
	return store;
}

const customRule: GestureRule = {
	id: 'custom-1',
	pattern: { gesture: 'tap', target: 'node' },
	actionId: 'my-custom-action',
};

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

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

	describe('gestureRulesAtom', () => {
		it('returns defaults when no custom rules', () => {
			const rules = store.get(gestureRulesAtom);
			expect(rules.length).toBeGreaterThan(0);
			expect(rules.some((r) => r.id === 'tap-node')).toBe(true);
		});

		it('merges custom rules into defaults', () => {
			store.set(addGestureRuleAtom, customRule);
			const rules = store.get(gestureRulesAtom);
			expect(rules.some((r) => r.id === 'custom-1')).toBe(true);
		});

		it('custom rules override defaults by id', () => {
			const override: GestureRule = {
				id: 'tap-node',
				pattern: { gesture: 'tap', target: 'node' },
				actionId: 'overridden-action',
			};
			store.set(addGestureRuleAtom, override);
			const rules = store.get(gestureRulesAtom);
			const tapNode = rules.find((r) => r.id === 'tap-node');
			expect(tapNode?.actionId).toBe('overridden-action');
		});

		it('consumer rules take highest priority', () => {
			const consumerRule: GestureRule = {
				id: 'tap-node',
				pattern: { gesture: 'tap', target: 'node' },
				actionId: 'consumer-override',
			};
			store.set(consumerGestureRulesAtom, [consumerRule]);
			const rules = store.get(gestureRulesAtom);
			const tapNode = rules.find((r) => r.id === 'tap-node');
			expect(tapNode?.actionId).toBe('consumer-override');
		});
	});

	describe('gestureRuleIndexAtom', () => {
		it('builds a non-empty index', () => {
			const index = store.get(gestureRuleIndexAtom);
			expect(index.size).toBeGreaterThan(0);
		});
	});

	describe('palmRejectionEnabledAtom', () => {
		it('defaults to true', () => {
			expect(store.get(palmRejectionEnabledAtom)).toBe(true);
		});

		it('can be toggled off', () => {
			store.set(palmRejectionEnabledAtom, false);
			expect(store.get(palmRejectionEnabledAtom)).toBe(false);
		});
	});

	describe('CRUD atoms', () => {
		it('addGestureRuleAtom adds a rule', () => {
			store.set(addGestureRuleAtom, customRule);
			const settings = store.get(gestureRuleSettingsAtom);
			expect(settings.customRules).toHaveLength(1);
		});

		it('addGestureRuleAtom replaces existing by id', () => {
			store.set(addGestureRuleAtom, customRule);
			store.set(addGestureRuleAtom, { ...customRule, actionId: 'updated' });
			const settings = store.get(gestureRuleSettingsAtom);
			expect(settings.customRules).toHaveLength(1);
			expect(settings.customRules[0].actionId).toBe('updated');
		});

		it('removeGestureRuleAtom removes by id', () => {
			store.set(addGestureRuleAtom, customRule);
			store.set(removeGestureRuleAtom, 'custom-1');
			expect(store.get(gestureRuleSettingsAtom).customRules).toHaveLength(0);
		});

		it('updateGestureRuleAtom patches a rule', () => {
			store.set(addGestureRuleAtom, customRule);
			store.set(updateGestureRuleAtom, { id: 'custom-1', updates: { actionId: 'patched' } });
			expect(store.get(gestureRuleSettingsAtom).customRules[0].actionId).toBe('patched');
		});

		it('resetGestureRulesAtom clears custom rules', () => {
			store.set(addGestureRuleAtom, customRule);
			store.set(resetGestureRulesAtom);
			expect(store.get(gestureRuleSettingsAtom).customRules).toHaveLength(0);
		});
	});
});
