import { describe, it, expect, beforeEach } from 'vitest';
import { commandRegistry } from '../commands/registry';
import type { CommandDefinition } from '../commands/types';

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

describe('CommandRegistry', () => {
	beforeEach(() => {
		commandRegistry.clear();
	});

	it('starts empty', () => {
		expect(commandRegistry.size).toBe(0);
	});

	it('register adds a command', () => {
		commandRegistry.register(makeCommand('test'));
		expect(commandRegistry.size).toBe(1);
		expect(commandRegistry.has('test')).toBe(true);
	});

	it('get retrieves by name', () => {
		commandRegistry.register(makeCommand('foo'));
		const cmd = commandRegistry.get('foo');
		expect(cmd?.name).toBe('foo');
	});

	it('get retrieves by alias', () => {
		commandRegistry.register(makeCommand('deleteNode', { aliases: ['dn', 'rmnode'] }));
		expect(commandRegistry.get('dn')?.name).toBe('deleteNode');
		expect(commandRegistry.get('rmnode')?.name).toBe('deleteNode');
	});

	it('get returns undefined for unknown', () => {
		expect(commandRegistry.get('nonexistent')).toBeUndefined();
	});

	it('unregister removes command and aliases', () => {
		commandRegistry.register(makeCommand('temp', { aliases: ['t'] }));
		expect(commandRegistry.has('t')).toBe(true);
		commandRegistry.unregister('temp');
		expect(commandRegistry.has('temp')).toBe(false);
		expect(commandRegistry.has('t')).toBe(false);
	});

	it('register throws on duplicate name', () => {
		commandRegistry.register(makeCommand('dup'));
		expect(() => commandRegistry.register(makeCommand('dup'))).toThrow('already registered');
	});

	it('all returns sorted by name', () => {
		commandRegistry.register(makeCommand('b-cmd'));
		commandRegistry.register(makeCommand('a-cmd'));
		const all = commandRegistry.all();
		expect(all[0].name).toBe('a-cmd');
		expect(all[1].name).toBe('b-cmd');
	});

	it('search returns all commands for empty query', () => {
		commandRegistry.register(makeCommand('alpha'));
		commandRegistry.register(makeCommand('beta'));
		const results = commandRegistry.search('');
		expect(results).toHaveLength(2);
	});

	it('search ranks exact match highest', () => {
		commandRegistry.register(makeCommand('node'));
		commandRegistry.register(makeCommand('createNode'));
		const results = commandRegistry.search('node');
		expect(results[0].name).toBe('node');
	});

	it('search matches description', () => {
		commandRegistry.register(makeCommand('x', { description: 'handle viewport' }));
		const results = commandRegistry.search('viewport');
		expect(results).toHaveLength(1);
	});
});
