/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, afterEach, vi } from 'vitest';
import * as path from 'node:path';
import mock from 'mock-fs';
import { FileCommandLoader } from './FileCommandLoader.js';
import { Storage } from '@hoptrendy/hopcode-core';
describe('FileCommandLoader - Extension Commands Support', () => {
    const projectRoot = '/test/project';
    const userCommandsDir = Storage.getUserCommandsDir();
    const projectCommandsDir = path.join(projectRoot, '.hopcode', 'commands');
    afterEach(() => {
        mock.restore();
    });
    it('should load commands from extension with config.commands path', async () => {
        const extensionDir = path.join(projectRoot, '.hopcode', 'extensions', 'test-ext');
        const extensionConfig = {
            name: 'test-ext',
            version: '1.0.0',
            commands: 'custom-cmds',
        };
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [extensionDir]: {
                'hopcode-extension.json': JSON.stringify(extensionConfig),
                'custom-cmds': {
                    'test.md': '---\ndescription: Test command from extension\n---\nDo something',
                },
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'test-ext',
                    config: extensionConfig,
                    name: 'test-ext',
                    version: '1.0.0',
                    isActive: true,
                    path: extensionDir,
                    contextFiles: [],
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        expect(commands).toHaveLength(1);
        expect(commands[0].name).toBe('test');
        expect(commands[0].extensionName).toBe('test-ext');
        expect(commands[0].description).toBe('[test-ext] Test command from extension');
    });
    it('should load commands from extension with multiple commands paths', async () => {
        const extensionDir = path.join(projectRoot, '.hopcode', 'extensions', 'multi-ext');
        const extensionConfig = {
            name: 'multi-ext',
            version: '1.0.0',
            commands: ['commands1', 'commands2'],
        };
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [extensionDir]: {
                'hopcode-extension.json': JSON.stringify(extensionConfig),
                commands1: {
                    'cmd1.md': '---\n---\nCommand 1',
                },
                commands2: {
                    'cmd2.md': '---\n---\nCommand 2',
                },
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'multi-ext',
                    config: extensionConfig,
                    contextFiles: [],
                    name: 'multi-ext',
                    version: '1.0.0',
                    isActive: true,
                    path: extensionDir,
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        expect(commands).toHaveLength(2);
        const commandNames = commands.map((c) => c.name).sort();
        expect(commandNames).toEqual(['cmd1', 'cmd2']);
        expect(commands.every((c) => c.extensionName === 'multi-ext')).toBe(true);
    });
    it('should fallback to default "commands" directory when config.commands not specified', async () => {
        const extensionDir = path.join(projectRoot, '.hopcode', 'extensions', 'default-ext');
        const extensionConfig = {
            name: 'default-ext',
            version: '1.0.0',
        };
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [extensionDir]: {
                'hopcode-extension.json': JSON.stringify(extensionConfig),
                commands: {
                    'default.md': '---\n---\nDefault command',
                },
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'default-ext',
                    config: extensionConfig,
                    contextFiles: [],
                    name: 'default-ext',
                    version: '1.0.0',
                    isActive: true,
                    path: extensionDir,
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        expect(commands).toHaveLength(1);
        expect(commands[0].name).toBe('default');
        expect(commands[0].extensionName).toBe('default-ext');
    });
    it('should handle extension without commands directory gracefully', async () => {
        const extensionDir = path.join(projectRoot, '.hopcode', 'extensions', 'no-cmds-ext');
        const extensionConfig = {
            name: 'no-cmds-ext',
            version: '1.0.0',
        };
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [extensionDir]: {
                'hopcode-extension.json': JSON.stringify(extensionConfig),
                // No commands directory
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'no-cmds-ext',
                    config: extensionConfig,
                    contextFiles: [],
                    name: 'no-cmds-ext',
                    version: '1.0.0',
                    isActive: true,
                    path: extensionDir,
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        // Should not throw and return empty array
        expect(commands).toHaveLength(0);
    });
    it('should set extensionName property for extension commands', async () => {
        const extensionDir = path.join(projectRoot, '.hopcode', 'extensions', 'prefix-ext');
        const extensionConfig = {
            name: 'prefix-ext',
            version: '1.0.0',
        };
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [extensionDir]: {
                'hopcode-extension.json': JSON.stringify(extensionConfig),
                commands: {
                    'mycommand.md': '---\n---\nMy command',
                },
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'prefix-ext',
                    config: extensionConfig,
                    contextFiles: [],
                    name: 'prefix-ext',
                    version: '1.0.0',
                    isActive: true,
                    path: extensionDir,
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        expect(commands).toHaveLength(1);
        expect(commands[0].name).toBe('mycommand');
        expect(commands[0].extensionName).toBe('prefix-ext');
        expect(commands[0].description).toMatch(/^\[prefix-ext\]/);
    });
    it('should load commands from multiple extensions in alphabetical order', async () => {
        const ext1Dir = path.join(projectRoot, '.hopcode', 'extensions', 'ext-b');
        const ext2Dir = path.join(projectRoot, '.hopcode', 'extensions', 'ext-a');
        mock({
            [userCommandsDir]: {},
            [projectCommandsDir]: {},
            [ext1Dir]: {
                'hopcode-extension.json': JSON.stringify({
                    name: 'ext-b',
                    version: '1.0.0',
                }),
                commands: {
                    'cmd.md': '---\n---\nCommand B',
                },
            },
            [ext2Dir]: {
                'hopcode-extension.json': JSON.stringify({
                    name: 'ext-a',
                    version: '1.0.0',
                }),
                commands: {
                    'cmd.md': '---\n---\nCommand A',
                },
            },
        });
        const mockConfig = {
            getFolderTrustFeature: vi.fn(() => false),
            getFolderTrust: vi.fn(() => true),
            getProjectRoot: vi.fn(() => projectRoot),
            storage: new Storage(projectRoot),
            getExtensions: vi.fn(() => [
                {
                    id: 'ext-b',
                    config: { name: 'ext-b', version: '1.0.0' },
                    contextFiles: [],
                    name: 'ext-b',
                    version: '1.0.0',
                    isActive: true,
                    path: ext1Dir,
                },
                {
                    id: 'ext-a',
                    config: { name: 'ext-a', version: '1.0.0' },
                    contextFiles: [],
                    name: 'ext-a',
                    version: '1.0.0',
                    isActive: true,
                    path: ext2Dir,
                },
            ]),
        };
        const loader = new FileCommandLoader(mockConfig);
        const commands = await loader.loadCommands(new AbortController().signal);
        expect(commands).toHaveLength(2);
        // Extensions are sorted alphabetically, so ext-a comes before ext-b
        expect(commands[0].extensionName).toBe('ext-a');
        expect(commands[1].extensionName).toBe('ext-b');
    });
});
//# sourceMappingURL=FileCommandLoader-extension.test.js.map