/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
import { act } from 'react';
import { renderHook } from '../../test-utils/render.js';
import { usePermissionsModifyTrust } from './usePermissionsModifyTrust.js';
import { TrustLevel, } from '../../config/trustedFolders.js';
import { coreEvents } from '@google/gemini-cli-core';
// Hoist mocks
const mockedCwd = vi.hoisted(() => vi.fn());
const mockedLoadTrustedFolders = vi.hoisted(() => vi.fn());
const mockedIsWorkspaceTrusted = vi.hoisted(() => vi.fn());
const mockedUseSettings = vi.hoisted(() => vi.fn());
// Mock modules
vi.mock('node:process', () => {
    const mockProcess = {
        cwd: mockedCwd,
        env: {},
    };
    return {
        ...mockProcess,
        default: mockProcess,
    };
});
vi.mock('node:path', async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...(actual && typeof actual === 'object' ? actual : {}),
        resolve: vi.fn((p) => p),
        join: vi.fn((...args) => args.join('/')),
    };
});
vi.mock('../../config/trustedFolders.js', () => ({
    loadTrustedFolders: mockedLoadTrustedFolders,
    isWorkspaceTrusted: mockedIsWorkspaceTrusted,
    TrustLevel: {
        TRUST_FOLDER: 'TRUST_FOLDER',
        TRUST_PARENT: 'TRUST_PARENT',
        DO_NOT_TRUST: 'DO_NOT_TRUST',
    },
}));
vi.mock('../contexts/SettingsContext.js', () => ({
    useSettings: mockedUseSettings,
}));
describe('usePermissionsModifyTrust', () => {
    let mockOnExit;
    let mockAddItem;
    beforeEach(() => {
        mockAddItem = vi.fn();
        mockOnExit = vi.fn();
        mockedCwd.mockReturnValue('/test/dir');
        mockedUseSettings.mockReturnValue({
            merged: {
                security: {
                    folderTrust: {
                        enabled: true,
                    },
                },
            },
        });
        mockedIsWorkspaceTrusted.mockReturnValue({
            isTrusted: undefined,
            source: undefined,
        });
    });
    afterEach(() => {
        vi.resetAllMocks();
    });
    describe('when targetDirectory is the current workspace', () => {
        it('should initialize with the correct trust level', () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: { '/test/dir': TrustLevel.TRUST_FOLDER } },
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            expect(result.current.currentTrustLevel).toBe(TrustLevel.TRUST_FOLDER);
        });
        it('should detect inherited trust from parent', () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: vi.fn(),
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            expect(result.current.isInheritedTrustFromParent).toBe(true);
            expect(result.current.isInheritedTrustFromIde).toBe(false);
        });
        it('should detect inherited trust from IDE', () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} }, // No explicit trust
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'ide',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            expect(result.current.isInheritedTrustFromIde).toBe(true);
            expect(result.current.isInheritedTrustFromParent).toBe(false);
        });
        it('should set needsRestart but not save when trust changes', async () => {
            const mockSetValue = vi.fn();
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: mockSetValue,
            });
            mockedIsWorkspaceTrusted
                .mockReturnValueOnce({ isTrusted: false, source: 'file' })
                .mockReturnValueOnce({ isTrusted: true, source: 'file' });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
            });
            expect(result.current.needsRestart).toBe(true);
            expect(mockSetValue).not.toHaveBeenCalled();
        });
        it('should save immediately if trust does not change', async () => {
            const mockSetValue = vi.fn();
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: mockSetValue,
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
            });
            expect(result.current.needsRestart).toBe(false);
            expect(mockSetValue).toHaveBeenCalledWith('/test/dir', TrustLevel.TRUST_PARENT);
            expect(mockOnExit).toHaveBeenCalled();
        });
        it('should commit the pending trust level change', async () => {
            const mockSetValue = vi.fn();
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: mockSetValue,
            });
            mockedIsWorkspaceTrusted
                .mockReturnValueOnce({ isTrusted: false, source: 'file' })
                .mockReturnValueOnce({ isTrusted: true, source: 'file' });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
            });
            expect(result.current.needsRestart).toBe(true);
            await act(async () => {
                await result.current.commitTrustLevelChange();
            });
            expect(mockSetValue).toHaveBeenCalledWith('/test/dir', TrustLevel.TRUST_FOLDER);
        });
        it('should add warning when setting DO_NOT_TRUST but still trusted by parent', async () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: vi.fn(),
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
            });
            expect(mockAddItem).toHaveBeenCalledWith({
                type: 'warning',
                text: 'Note: This folder is still trusted because a parent folder is trusted.',
            }, expect.any(Number));
        });
        it('should add warning when setting DO_NOT_TRUST but still trusted by IDE', async () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: vi.fn(),
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'ide',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
            });
            expect(mockAddItem).toHaveBeenCalledWith({
                type: 'warning',
                text: 'Note: This folder is still trusted because the connected IDE workspace is trusted.',
            }, expect.any(Number));
        });
    });
    describe('when targetDirectory is not the current workspace', () => {
        const otherDirectory = '/other/dir';
        it('should not detect inherited trust', () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, otherDirectory));
            expect(result.current.isInheritedTrustFromParent).toBe(false);
            expect(result.current.isInheritedTrustFromIde).toBe(false);
        });
        it('should save immediately without needing a restart', async () => {
            const mockSetValue = vi.fn();
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: mockSetValue,
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: false,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, otherDirectory));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
            });
            expect(result.current.needsRestart).toBe(false);
            expect(mockSetValue).toHaveBeenCalledWith(otherDirectory, TrustLevel.TRUST_FOLDER);
            expect(mockOnExit).toHaveBeenCalled();
        });
        it('should not add a warning when setting DO_NOT_TRUST', async () => {
            mockedLoadTrustedFolders.mockReturnValue({
                user: { config: {} },
                setValue: vi.fn(),
            });
            mockedIsWorkspaceTrusted.mockReturnValue({
                isTrusted: true,
                source: 'file',
            });
            const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, otherDirectory));
            await act(async () => {
                await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
            });
            expect(mockAddItem).not.toHaveBeenCalled();
        });
    });
    it('should emit feedback when setValue throws in updateTrustLevel', async () => {
        const mockSetValue = vi.fn().mockImplementation(() => {
            throw new Error('test error');
        });
        mockedLoadTrustedFolders.mockReturnValue({
            user: { config: {} },
            setValue: mockSetValue,
        });
        mockedIsWorkspaceTrusted.mockReturnValue({
            isTrusted: true,
            source: 'file',
        });
        const emitFeedbackSpy = vi.spyOn(coreEvents, 'emitFeedback');
        const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
        await act(async () => {
            await result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
        });
        expect(emitFeedbackSpy).toHaveBeenCalledWith('error', 'Failed to save trust settings. Your changes may not persist.');
        expect(mockOnExit).toHaveBeenCalled();
    });
    it('should emit feedback when setValue throws in commitTrustLevelChange', async () => {
        const mockSetValue = vi.fn().mockImplementation(() => {
            throw new Error('test error');
        });
        mockedLoadTrustedFolders.mockReturnValue({
            user: { config: {} },
            setValue: mockSetValue,
        });
        mockedIsWorkspaceTrusted
            .mockReturnValueOnce({ isTrusted: false, source: 'file' })
            .mockReturnValueOnce({ isTrusted: true, source: 'file' });
        const emitFeedbackSpy = vi.spyOn(coreEvents, 'emitFeedback');
        const { result } = renderHook(() => usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()));
        await act(async () => {
            await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
        });
        await act(async () => {
            const success = await result.current.commitTrustLevelChange();
            expect(success).toBe(false);
        });
        expect(emitFeedbackSpy).toHaveBeenCalledWith('error', 'Failed to save trust settings. Your changes may not persist.');
        expect(result.current.needsRestart).toBe(false);
    });
});
//# sourceMappingURL=usePermissionsModifyTrust.test.js.map