import { describe, it, expect, vi, beforeEach } from 'vitest';
import { SelfUpdateCliGateway } from '../../../../modules/cli-configuration/interface-adapters/gateways/selfUpdate.cli.gateway.js';
import { writePidFile, removePidFile } from '../../../../shared/services/pidFileManager.js';
import { PID_FILE_PATH } from '../../../../shared/services/daemonPaths.js';
function createFakeDependencies(overrides) {
    return {
        execFileAsync: vi.fn().mockResolvedValue({ stdout: '', stderr: '' }),
        killProcess: vi.fn(),
        spawnDaemonDelayed: vi.fn(),
        ...overrides,
    };
}
describe('SelfUpdateCliGateway', () => {
    beforeEach(() => {
        removePidFile(PID_FILE_PATH);
    });
    describe('runGlobalUpdate', () => {
        it('should return success when npm update succeeds', async () => {
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            const result = await gateway.runGlobalUpdate();
            expect(result.success).toBe(true);
            expect(result.permissionDenied).toBe(false);
            expect(deps.execFileAsync).toHaveBeenCalledWith('npm', ['update', '-g', 'reviewflow']);
        });
        it('should return permissionDenied true on EACCES error', async () => {
            const deps = createFakeDependencies({
                execFileAsync: vi.fn().mockRejectedValue(new Error('EACCES: permission denied')),
            });
            const gateway = new SelfUpdateCliGateway(deps);
            const result = await gateway.runGlobalUpdate();
            expect(result.success).toBe(false);
            expect(result.permissionDenied).toBe(true);
            expect(result.error).toBe('EACCES: permission denied');
        });
        it('should return permissionDenied false on non-EACCES error', async () => {
            const deps = createFakeDependencies({
                execFileAsync: vi.fn().mockRejectedValue(new Error('network error')),
            });
            const gateway = new SelfUpdateCliGateway(deps);
            const result = await gateway.runGlobalUpdate();
            expect(result.success).toBe(false);
            expect(result.permissionDenied).toBe(false);
            expect(result.error).toBe('network error');
        });
    });
    describe('restartDaemon', () => {
        it('should use server port when no pid file exists', async () => {
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            expect(deps.spawnDaemonDelayed).toHaveBeenCalledWith(3847, expect.any(Number));
        });
        it('should use pid file port over server port when pid file exists', async () => {
            writePidFile(PID_FILE_PATH, { pid: 9999, startedAt: new Date().toISOString(), port: 4000 });
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            expect(deps.spawnDaemonDelayed).toHaveBeenCalledWith(4000, expect.any(Number));
        });
        it('should kill process from pid file when it exists', async () => {
            writePidFile(PID_FILE_PATH, { pid: 9999, startedAt: new Date().toISOString(), port: 4000 });
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            expect(deps.killProcess).toHaveBeenCalledWith(9999, 'SIGTERM');
        });
        it('should kill current process when no pid file exists', async () => {
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            expect(deps.killProcess).toHaveBeenCalledWith(process.pid, 'SIGTERM');
        });
        it('should spawn delayed daemon before killing process', async () => {
            const callOrder = [];
            const deps = createFakeDependencies({
                spawnDaemonDelayed: vi.fn(() => { callOrder.push('spawn'); }),
                killProcess: vi.fn(() => { callOrder.push('kill'); }),
            });
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            expect(callOrder).toEqual(['spawn', 'kill']);
        });
        it('should not throw when kill process fails', async () => {
            const deps = createFakeDependencies({
                killProcess: vi.fn(() => { throw new Error('No such process'); }),
            });
            const gateway = new SelfUpdateCliGateway(deps);
            await expect(gateway.restartDaemon(3847)).resolves.not.toThrow();
        });
        it('should remove pid file before spawning', async () => {
            writePidFile(PID_FILE_PATH, { pid: 9999, startedAt: new Date().toISOString(), port: 4000 });
            const deps = createFakeDependencies();
            const gateway = new SelfUpdateCliGateway(deps);
            await gateway.restartDaemon(3847);
            const { readPidFile } = await import('../../../../shared/services/pidFileManager.js');
            expect(readPidFile(PID_FILE_PATH)).toBeNull();
        });
    });
});
//# sourceMappingURL=selfUpdate.cli.gateway.test.js.map