/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { vi, describe, it, expect, beforeEach } from 'vitest';
import { memoryCommand } from './memoryCommand.js';
import { createMockCommandContext } from '../../test-utils/mockCommandContext.js';
import { MessageType } from '../types.js';
import { getErrorMessage, SimpleExtensionLoader, } from 'sixth-cli-core';
import { loadHierarchicalGeminiMemory } from '../../config/config.js';
vi.mock('sixth-cli-core', async (importOriginal) => {
    const original = await importOriginal();
    return {
        ...original,
        getErrorMessage: vi.fn((error) => {
            if (error instanceof Error)
                return error.message;
            return String(error);
        }),
    };
});
vi.mock('../../config/config.js', async (importOriginal) => {
    const original = await importOriginal();
    return {
        ...original,
        loadHierarchicalGeminiMemory: vi.fn(),
    };
});
const mockLoadHierarchicalGeminiMemory = loadHierarchicalGeminiMemory;
describe('memoryCommand', () => {
    let mockContext;
    const getSubCommand = (name) => {
        const subCommand = memoryCommand.subCommands?.find((cmd) => cmd.name === name);
        if (!subCommand) {
            throw new Error(`/memory ${name} command not found.`);
        }
        return subCommand;
    };
    describe('/memory show', () => {
        let showCommand;
        let mockGetUserMemory;
        let mockGetGeminiMdFileCount;
        beforeEach(() => {
            showCommand = getSubCommand('show');
            mockGetUserMemory = vi.fn();
            mockGetGeminiMdFileCount = vi.fn();
            mockContext = createMockCommandContext({
                services: {
                    config: {
                        getUserMemory: mockGetUserMemory,
                        getGeminiMdFileCount: mockGetGeminiMdFileCount,
                        getExtensionLoader: () => new SimpleExtensionLoader([]),
                    },
                },
            });
        });
        it('should display a message if memory is empty', async () => {
            if (!showCommand.action)
                throw new Error('Command has no action');
            mockGetUserMemory.mockReturnValue('');
            mockGetGeminiMdFileCount.mockReturnValue(0);
            await showCommand.action(mockContext, '');
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'Memory is currently empty.',
            }, expect.any(Number));
        });
        it('should display the memory content and file count if it exists', async () => {
            if (!showCommand.action)
                throw new Error('Command has no action');
            const memoryContent = 'This is a test memory.';
            mockGetUserMemory.mockReturnValue(memoryContent);
            mockGetGeminiMdFileCount.mockReturnValue(1);
            await showCommand.action(mockContext, '');
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: `Current memory content from 1 file(s):\n\n---\n${memoryContent}\n---`,
            }, expect.any(Number));
        });
    });
    describe('/memory add', () => {
        let addCommand;
        beforeEach(() => {
            addCommand = getSubCommand('add');
            mockContext = createMockCommandContext();
        });
        it('should return an error message if no arguments are provided', () => {
            if (!addCommand.action)
                throw new Error('Command has no action');
            const result = addCommand.action(mockContext, '  ');
            expect(result).toEqual({
                type: 'message',
                messageType: 'error',
                content: 'Usage: /memory add <text to remember>',
            });
            expect(mockContext.ui.addItem).not.toHaveBeenCalled();
        });
        it('should return a tool action and add an info message when arguments are provided', () => {
            if (!addCommand.action)
                throw new Error('Command has no action');
            const fact = 'remember this';
            const result = addCommand.action(mockContext, `  ${fact}  `);
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: `Attempting to save to memory: "${fact}"`,
            }, expect.any(Number));
            expect(result).toEqual({
                type: 'tool',
                toolName: 'save_memory',
                toolArgs: { fact },
            });
        });
    });
    describe('/memory refresh', () => {
        let refreshCommand;
        let mockSetUserMemory;
        let mockSetGeminiMdFileCount;
        let mockSetGeminiMdFilePaths;
        beforeEach(() => {
            refreshCommand = getSubCommand('refresh');
            mockSetUserMemory = vi.fn();
            mockSetGeminiMdFileCount = vi.fn();
            mockSetGeminiMdFilePaths = vi.fn();
            const mockConfig = {
                setUserMemory: mockSetUserMemory,
                setGeminiMdFileCount: mockSetGeminiMdFileCount,
                setGeminiMdFilePaths: mockSetGeminiMdFilePaths,
                getWorkingDir: () => '/test/dir',
                getDebugMode: () => false,
                getFileService: () => ({}),
                getExtensionLoader: () => new SimpleExtensionLoader([]),
                getExtensions: () => [],
                shouldLoadMemoryFromIncludeDirectories: () => false,
                getWorkspaceContext: () => ({
                    getDirectories: () => [],
                }),
                getFileFilteringOptions: () => ({
                    ignore: [],
                    include: [],
                }),
                isTrustedFolder: () => false,
            };
            mockContext = createMockCommandContext({
                services: {
                    config: mockConfig,
                    settings: {
                        merged: {
                            memoryDiscoveryMaxDirs: 1000,
                            context: {
                                importFormat: 'tree',
                            },
                        },
                    },
                },
                ui: {
                    setGeminiMdFileCount: vi.fn(),
                },
            });
            mockLoadHierarchicalGeminiMemory.mockClear();
        });
        it('should display success message when memory is refreshed with content', async () => {
            if (!refreshCommand.action)
                throw new Error('Command has no action');
            const refreshResult = {
                memoryContent: 'new memory content',
                fileCount: 2,
                filePaths: ['/path/one/GEMINI.md', '/path/two/GEMINI.md'],
            };
            mockLoadHierarchicalGeminiMemory.mockResolvedValue(refreshResult);
            await refreshCommand.action(mockContext, '');
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'Refreshing memory from source files...',
            }, expect.any(Number));
            expect(mockLoadHierarchicalGeminiMemory).toHaveBeenCalledOnce();
            expect(mockSetUserMemory).toHaveBeenCalledWith(refreshResult.memoryContent);
            expect(mockSetGeminiMdFileCount).toHaveBeenCalledWith(refreshResult.fileCount);
            expect(mockSetGeminiMdFilePaths).toHaveBeenCalledWith(refreshResult.filePaths);
            expect(mockContext.ui.setGeminiMdFileCount).toHaveBeenCalledWith(refreshResult.fileCount);
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'Memory refreshed successfully. Loaded 18 characters from 2 file(s).',
            }, expect.any(Number));
        });
        it('should display success message when memory is refreshed with no content', async () => {
            if (!refreshCommand.action)
                throw new Error('Command has no action');
            const refreshResult = { memoryContent: '', fileCount: 0, filePaths: [] };
            mockLoadHierarchicalGeminiMemory.mockResolvedValue(refreshResult);
            await refreshCommand.action(mockContext, '');
            expect(mockLoadHierarchicalGeminiMemory).toHaveBeenCalledOnce();
            expect(mockSetUserMemory).toHaveBeenCalledWith('');
            expect(mockSetGeminiMdFileCount).toHaveBeenCalledWith(0);
            expect(mockSetGeminiMdFilePaths).toHaveBeenCalledWith([]);
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'Memory refreshed successfully. No memory content found.',
            }, expect.any(Number));
        });
        it('should display an error message if refreshing fails', async () => {
            if (!refreshCommand.action)
                throw new Error('Command has no action');
            const error = new Error('Failed to read memory files.');
            mockLoadHierarchicalGeminiMemory.mockRejectedValue(error);
            await refreshCommand.action(mockContext, '');
            expect(mockLoadHierarchicalGeminiMemory).toHaveBeenCalledOnce();
            expect(mockSetUserMemory).not.toHaveBeenCalled();
            expect(mockSetGeminiMdFileCount).not.toHaveBeenCalled();
            expect(mockSetGeminiMdFilePaths).not.toHaveBeenCalled();
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.ERROR,
                text: `Error refreshing memory: ${error.message}`,
            }, expect.any(Number));
            expect(getErrorMessage).toHaveBeenCalledWith(error);
        });
        it('should not throw if config service is unavailable', async () => {
            if (!refreshCommand.action)
                throw new Error('Command has no action');
            const nullConfigContext = createMockCommandContext({
                services: { config: null },
            });
            await expect(refreshCommand.action(nullConfigContext, '')).resolves.toBeUndefined();
            expect(nullConfigContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'Refreshing memory from source files...',
            }, expect.any(Number));
            expect(mockLoadHierarchicalGeminiMemory).not.toHaveBeenCalled();
        });
    });
    describe('/memory list', () => {
        let listCommand;
        let mockGetGeminiMdfilePaths;
        beforeEach(() => {
            listCommand = getSubCommand('list');
            mockGetGeminiMdfilePaths = vi.fn();
            mockContext = createMockCommandContext({
                services: {
                    config: {
                        getGeminiMdFilePaths: mockGetGeminiMdfilePaths,
                    },
                },
            });
        });
        it('should display a message if no GEMINI.md files are found', async () => {
            if (!listCommand.action)
                throw new Error('Command has no action');
            mockGetGeminiMdfilePaths.mockReturnValue([]);
            await listCommand.action(mockContext, '');
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: 'No GEMINI.md files in use.',
            }, expect.any(Number));
        });
        it('should display the file count and paths if they exist', async () => {
            if (!listCommand.action)
                throw new Error('Command has no action');
            const filePaths = ['/path/one/GEMINI.md', '/path/two/GEMINI.md'];
            mockGetGeminiMdfilePaths.mockReturnValue(filePaths);
            await listCommand.action(mockContext, '');
            expect(mockContext.ui.addItem).toHaveBeenCalledWith({
                type: MessageType.INFO,
                text: `There are 2 GEMINI.md file(s) in use:\n\n${filePaths.join('\n')}`,
            }, expect.any(Number));
        });
    });
});
//# sourceMappingURL=memoryCommand.test.js.map