/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { terminalSetup, VSCODE_SHIFT_ENTER_SEQUENCE, shouldPromptForTerminalSetup, } from './terminalSetup.js';
import { terminalCapabilityManager } from './terminalCapabilityManager.js';
// Mock dependencies
const mocks = vi.hoisted(() => ({
    exec: vi.fn(),
    mkdir: vi.fn(),
    readFile: vi.fn(),
    writeFile: vi.fn(),
    copyFile: vi.fn(),
    homedir: vi.fn(),
    platform: vi.fn(),
    writeStream: {
        write: vi.fn(),
        on: vi.fn(),
    },
}));
vi.mock('node:child_process', () => ({
    exec: mocks.exec,
    execFile: vi.fn(),
}));
vi.mock('node:fs', () => ({
    createWriteStream: () => mocks.writeStream,
    promises: {
        mkdir: mocks.mkdir,
        readFile: mocks.readFile,
        writeFile: mocks.writeFile,
        copyFile: mocks.copyFile,
    },
}));
vi.mock('node:os', () => ({
    homedir: mocks.homedir,
    platform: mocks.platform,
}));
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        homedir: mocks.homedir,
    };
});
vi.mock('./terminalCapabilityManager.js', () => ({
    terminalCapabilityManager: {
        isKittyProtocolEnabled: vi.fn().mockReturnValue(false),
    },
}));
describe('terminalSetup', () => {
    beforeEach(() => {
        vi.resetAllMocks();
        vi.stubEnv('TERM_PROGRAM', '');
        vi.stubEnv('CURSOR_TRACE_ID', '');
        vi.stubEnv('VSCODE_GIT_ASKPASS_MAIN', '');
        vi.stubEnv('VSCODE_GIT_IPC_HANDLE', '');
        // Default mocks
        mocks.homedir.mockReturnValue('/home/user');
        mocks.platform.mockReturnValue('darwin');
        mocks.mkdir.mockResolvedValue(undefined);
        mocks.copyFile.mockResolvedValue(undefined);
        mocks.exec.mockImplementation((cmd, cb) => cb(null, { stdout: '' }));
    });
    afterEach(() => {
        vi.unstubAllEnvs();
    });
    describe('detectTerminal', () => {
        it('should detect VS Code from env var', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            const result = await terminalSetup();
            expect(result.message).toContain('VS Code');
        });
        it('should detect Cursor from env var', async () => {
            process.env['CURSOR_TRACE_ID'] = 'some-id';
            const result = await terminalSetup();
            expect(result.message).toContain('Cursor');
        });
        it('should detect Windsurf from env var', async () => {
            process.env['VSCODE_GIT_ASKPASS_MAIN'] = '/path/to/windsurf/askpass';
            const result = await terminalSetup();
            expect(result.message).toContain('Windsurf');
        });
        it('should detect from parent process', async () => {
            mocks.platform.mockReturnValue('linux');
            mocks.exec.mockImplementation((cmd, cb) => {
                cb(null, { stdout: 'code\n' });
            });
            const result = await terminalSetup();
            expect(result.message).toContain('VS Code');
        });
    });
    describe('configureVSCodeStyle', () => {
        it('should create new keybindings file if none exists', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            mocks.readFile.mockRejectedValue(new Error('ENOENT'));
            const result = await terminalSetup();
            expect(result.success).toBe(true);
            expect(mocks.writeFile).toHaveBeenCalled();
            const writtenContent = JSON.parse(mocks.writeFile.mock.calls[0][1]);
            expect(writtenContent).toMatchSnapshot();
        });
        it('should append to existing keybindings', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            mocks.readFile.mockResolvedValue('[]');
            const result = await terminalSetup();
            expect(result.success).toBe(true);
            const writtenContent = JSON.parse(mocks.writeFile.mock.calls[0][1]);
            expect(writtenContent).toHaveLength(6); // Shift+Enter, Ctrl+Enter, Cmd+Z, Alt+Z, Shift+Cmd+Z, Shift+Alt+Z
        });
        it('should not modify if bindings already exist', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            const existingBindings = [
                {
                    key: 'shift+enter',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: VSCODE_SHIFT_ENTER_SEQUENCE },
                },
                {
                    key: 'ctrl+enter',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: VSCODE_SHIFT_ENTER_SEQUENCE },
                },
                {
                    key: 'cmd+z',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: '\u001b[122;9u' },
                },
                {
                    key: 'alt+z',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: '\u001b[122;3u' },
                },
                {
                    key: 'shift+cmd+z',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: '\u001b[122;10u' },
                },
                {
                    key: 'shift+alt+z',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: '\u001b[122;4u' },
                },
            ];
            mocks.readFile.mockResolvedValue(JSON.stringify(existingBindings));
            const result = await terminalSetup();
            expect(result.success).toBe(true);
            expect(mocks.writeFile).not.toHaveBeenCalled();
        });
        it('should fail gracefully if json is invalid', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            mocks.readFile.mockResolvedValue('{ invalid json');
            const result = await terminalSetup();
            expect(result.success).toBe(false);
            expect(result.message).toContain('invalid JSON');
        });
        it('should handle comments in JSON', async () => {
            process.env['TERM_PROGRAM'] = 'vscode';
            const jsonWithComments = '// This is a comment\n[]';
            mocks.readFile.mockResolvedValue(jsonWithComments);
            const result = await terminalSetup();
            expect(result.success).toBe(true);
            expect(mocks.writeFile).toHaveBeenCalled();
        });
    });
    describe('shouldPromptForTerminalSetup', () => {
        it('should return false when kitty protocol is already enabled', async () => {
            vi.mocked(terminalCapabilityManager.isKittyProtocolEnabled).mockReturnValue(true);
            const result = await shouldPromptForTerminalSetup();
            expect(result).toBe(false);
        });
        it('should return false when both Shift+Enter and Ctrl+Enter bindings already exist', async () => {
            vi.mocked(terminalCapabilityManager.isKittyProtocolEnabled).mockReturnValue(false);
            process.env['TERM_PROGRAM'] = 'vscode';
            const existingBindings = [
                {
                    key: 'shift+enter',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: VSCODE_SHIFT_ENTER_SEQUENCE },
                },
                {
                    key: 'ctrl+enter',
                    command: 'workbench.action.terminal.sendSequence',
                    args: { text: VSCODE_SHIFT_ENTER_SEQUENCE },
                },
            ];
            mocks.readFile.mockResolvedValue(JSON.stringify(existingBindings));
            const result = await shouldPromptForTerminalSetup();
            expect(result).toBe(false);
        });
        it('should return true when keybindings file does not exist', async () => {
            vi.mocked(terminalCapabilityManager.isKittyProtocolEnabled).mockReturnValue(false);
            process.env['TERM_PROGRAM'] = 'vscode';
            mocks.readFile.mockRejectedValue(new Error('ENOENT'));
            const result = await shouldPromptForTerminalSetup();
            expect(result).toBe(true);
        });
    });
});
//# sourceMappingURL=terminalSetup.test.js.map