import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { afterEach, describe, expect, it, vi } from 'vitest';
const ptyWrite = vi.fn();
const ptyKill = vi.fn();
vi.mock('node-pty', () => ({
    spawn: vi.fn(() => ({
        write: ptyWrite,
        kill: ptyKill,
        onData: vi.fn(),
        onExit: vi.fn(),
    })),
}));
const currentDir = dirname(fileURLToPath(import.meta.url));
afterEach(async () => {
    const { closeAllPtySessions } = await import('./pty.js');
    closeAllPtySessions('test-cleanup');
    ptyWrite.mockClear();
    ptyKill.mockClear();
});
describe('ordinary PTY persistence policy', () => {
    it('falls back from non-interactive Linux login shells', async () => {
        const { resolveDefaultShell } = await import('./pty.js');
        expect(resolveDefaultShell('linux', { SHELL: '/usr/sbin/nologin' }, (candidate) => candidate === '/bin/bash')).toEqual({ shell: '/bin/bash', args: [] });
        expect(resolveDefaultShell('linux', { SHELL: '/bin/false' }, (candidate) => candidate === '/bin/sh')).toEqual({ shell: '/bin/sh', args: [] });
    });
    it('falls back when Linux SHELL points to a missing absolute path', async () => {
        const { resolveDefaultShell } = await import('./pty.js');
        expect(resolveDefaultShell('linux', { SHELL: '/missing/shell' }, (candidate) => candidate === '/bin/bash')).toEqual({ shell: '/bin/bash', args: [] });
    });
    it('keeps persistent dashboard PTY sessions alive across browser disconnects', () => {
        const source = readFileSync(resolve(currentDir, './pty.ts'), 'utf-8');
        expect(source).toContain('persistent: boolean');
        expect(source).toContain('persistent?: unknown');
        expect(source).toContain('persistent: input.persistent === true');
        expect(source).toContain('ownerUserId: String(input.ownerUserId || "").trim() || undefined');
        expect(source).toContain('tenantId: String(input.tenantId || "").trim() || undefined');
        expect(source).toContain('projectName: String(input.projectName || "").trim() || undefined');
        expect(source).toContain('if (!session.persistent) {');
        expect(source).toContain('resolvePtyExitedTtlMs');
        expect(source).toContain('closePtySession(session.id, "exited-timeout")');
        expect(source).toContain('session.sockets.size === 0 && session.status === "running" && !session.persistent');
    });
    it('documents optional pre-command injection without exposing template IDs', () => {
        const source = readFileSync(resolve(currentDir, './pty.ts'), 'utf-8');
        expect(source).toContain('preCommand?: unknown');
        expect(source).toContain('preCommand: record.preCommand');
        expect(source).toContain('injectPtyPreCommand(session, input.preCommand)');
        expect(source).toContain('command.replace(/\\n/g, "\\r")');
        expect(source).toContain('session.ptyProcess.write(payload)');
        expect(source).not.toContain('preCommandTemplateId');
    });
    it('writes multiline pre-commands as enter-separated PTY input', async () => {
        const { createPtySession } = await import('./pty.js');
        createPtySession({
            workspacePath: process.cwd(),
            preCommand: 'echo one\necho two',
            persistent: true,
        });
        expect(ptyWrite).toHaveBeenCalledTimes(1);
        expect(ptyWrite).toHaveBeenCalledWith('echo one\recho two\r');
    });
    it('normalizes a trailing LF to exactly one final PTY enter', async () => {
        const { createPtySession } = await import('./pty.js');
        createPtySession({
            workspacePath: process.cwd(),
            preCommand: 'echo one\n',
            persistent: true,
        });
        expect(ptyWrite).toHaveBeenCalledTimes(1);
        expect(ptyWrite).toHaveBeenCalledWith('echo one\r');
    });
    it('keeps no-template PTY creation from writing pre-command input', async () => {
        const { createPtySession } = await import('./pty.js');
        createPtySession({
            workspacePath: process.cwd(),
            persistent: true,
        });
        expect(ptyWrite).not.toHaveBeenCalled();
    });
});
