import { describe, it, expect, beforeEach } from 'vitest';
import { createStore } from 'jotai';
import { commandRegistry } from '../commands/registry';
import {
	commandLineVisibleAtom,
	commandLineStateAtom,
	inputModeAtom,
	commandFeedbackAtom,
	commandHistoryAtom,
	selectedSuggestionIndexAtom,
} from '../commands/store-atoms';
import {
	openCommandLineAtom,
	closeCommandLineAtom,
	updateSearchQueryAtom,
	selectCommandAtom,
	provideInputAtom,
	skipInputAtom,
	goBackInputAtom,
	setCommandErrorAtom,
	clearCommandErrorAtom,
} from '../commands/store';
import type { CommandDefinition } from '../commands/types';

function makeCommand(name: string, inputs: CommandDefinition['inputs'] = []): CommandDefinition {
	return {
		name,
		description: `Test: ${name}`,
		category: 'custom',
		inputs,
		execute: async () => {},
	};
}

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

	beforeEach(() => {
		store = createStore();
		commandRegistry.clear();
	});

	it('openCommandLineAtom sets visible and searching phase', () => {
		store.set(openCommandLineAtom);
		expect(store.get(commandLineVisibleAtom)).toBe(true);
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('searching');
	});

	it('closeCommandLineAtom resets state', () => {
		store.set(openCommandLineAtom);
		store.set(closeCommandLineAtom);
		expect(store.get(commandLineVisibleAtom)).toBe(false);
		expect(store.get(commandLineStateAtom).phase).toBe('idle');
		expect(store.get(commandFeedbackAtom)).toBeNull();
	});

	it('updateSearchQueryAtom filters suggestions', () => {
		commandRegistry.register(makeCommand('alpha'));
		commandRegistry.register(makeCommand('beta'));
		store.set(openCommandLineAtom);

		store.set(updateSearchQueryAtom, 'alpha');
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('searching');
		if (state.phase === 'searching') {
			expect(state.suggestions[0].name).toBe('alpha');
		}
	});

	it('updateSearchQueryAtom resets selection index', () => {
		store.set(openCommandLineAtom);
		store.set(updateSearchQueryAtom, 'test');
		expect(store.get(selectedSuggestionIndexAtom)).toBe(0);
	});

	it('selectCommandAtom with no inputs transitions to executing', () => {
		const cmd = makeCommand('noInputs');
		store.set(selectCommandAtom, cmd);
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('executing');
	});

	it('selectCommandAtom with inputs transitions to collecting', () => {
		const cmd = makeCommand('withInput', [
			{ name: 'target', type: 'node', prompt: 'Pick node' },
		]);
		store.set(selectCommandAtom, cmd);
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('collecting');
		if (state.phase === 'collecting') {
			expect(state.inputIndex).toBe(0);
		}
	});

	it('selectCommandAtom adds to history', () => {
		const cmd = makeCommand('historyTest');
		store.set(selectCommandAtom, cmd);
		expect(store.get(commandHistoryAtom)).toContain('historyTest');
	});

	it('provideInputAtom advances to next input', () => {
		const cmd = makeCommand('twoInputs', [
			{ name: 'first', type: 'text', prompt: 'Enter first' },
			{ name: 'second', type: 'text', prompt: 'Enter second' },
		]);
		store.set(selectCommandAtom, cmd);
		store.set(provideInputAtom, 'val1');
		const state = store.get(commandLineStateAtom);
		if (state.phase === 'collecting') {
			expect(state.inputIndex).toBe(1);
			expect(state.collected.first).toBe('val1');
		}
	});

	it('setCommandErrorAtom sets error phase', () => {
		store.set(setCommandErrorAtom, 'Something failed');
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('error');
		if (state.phase === 'error') {
			expect(state.message).toBe('Something failed');
		}
	});

	it('clearCommandErrorAtom resets to idle', () => {
		store.set(setCommandErrorAtom, 'err');
		store.set(clearCommandErrorAtom);
		expect(store.get(commandLineStateAtom).phase).toBe('idle');
	});

	it('goBackInputAtom returns to search from first input', () => {
		const cmd = makeCommand('backTest', [
			{ name: 'first', type: 'text', prompt: 'Enter' },
		]);
		store.set(selectCommandAtom, cmd);
		store.set(goBackInputAtom);
		const state = store.get(commandLineStateAtom);
		expect(state.phase).toBe('searching');
	});
});
