import { describe, it, expect, beforeEach } from 'vitest';
import { checkSupervisorAndRespawn } from '../../modules/supervisor-management/usecases/checkSupervisorAndRespawn.usecase.js';
import { StubSupervisorGateway } from '../../tests/stubs/supervisor.stub.js';
import { StubSupervisorLockGateway } from '../../tests/stubs/supervisorLock.stub.js';
import { InMemorySupervisorStatusStore } from '../../modules/supervisor-management/interface-adapters/gateways/supervisorStatusStore.memory.gateway.js';
import { createCapturingLogger } from '../../tests/stubs/capturingLogger.stub.js';
const fixedNow = new Date('2026-05-23T08:00:00Z');
describe('SPEC-172: Claude agents supervisor lifecycle (acceptance)', () => {
    let supervisorGateway;
    let lockGateway;
    let statusStore;
    let capturing;
    beforeEach(() => {
        supervisorGateway = new StubSupervisorGateway();
        lockGateway = new StubSupervisorLockGateway();
        statusStore = new InMemorySupervisorStatusStore();
        capturing = createCapturingLogger();
    });
    describe('Scenario 1: supervisor up at boot', () => {
        it('records state up and logs reachable, no spawn attempted', async () => {
            supervisorGateway.setProbeResult({ state: 'up', reason: null });
            const status = await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => fixedNow,
            });
            expect(status.state).toBe('up');
            expect(status.reason).toBeNull();
            expect(supervisorGateway.spawnCallCount).toBe(0);
            expect(capturing.infoMessages).toContain('Claude agents supervisor reachable');
            expect(statusStore.read().state).toBe('up');
        });
    });
    describe('Scenario 2: supervisor down at boot, spawn succeeds', () => {
        it('acquires the lock, spawns detached, logs the new PID, releases the lock', async () => {
            supervisorGateway.setProbeResult({ state: 'down', reason: 'exit code 1' });
            supervisorGateway.setSpawnResult({ state: 'spawned', pid: 12345, reason: null });
            const status = await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => fixedNow,
            });
            expect(supervisorGateway.spawnCallCount).toBe(1);
            expect(lockGateway.acquireCallCount).toBe(1);
            expect(lockGateway.releaseCallCount).toBe(1);
            expect(status.state).toBe('up');
            expect(capturing.infoMessages.some(message => message.includes('spawned'))).toBe(true);
            expect(capturing.infoMessages.some(message => message.includes('12345'))).toBe(true);
        });
    });
    describe('Scenario 3: supervisor down at boot, spawn fails (binary not found)', () => {
        it('records state down with reason supervisor-spawn-failed and logs a warning', async () => {
            supervisorGateway.setProbeResult({ state: 'down', reason: 'command not found' });
            supervisorGateway.setSpawnResult({
                state: 'failed',
                pid: null,
                reason: 'claude binary not found in PATH',
            });
            const status = await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => fixedNow,
            });
            expect(status.state).toBe('down');
            expect(status.reason).toBe('supervisor-spawn-failed');
            expect(capturing.warnMessages.length).toBeGreaterThan(0);
            expect(statusStore.read().reason).toBe('supervisor-spawn-failed');
            expect(lockGateway.releaseCallCount).toBe(1);
        });
    });
    describe('Scenario 4: periodic re-check transitions up to down', () => {
        it('logs a warning on the down transition and attempts a respawn', async () => {
            supervisorGateway.setProbeResult({ state: 'up', reason: null });
            await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => fixedNow,
            });
            expect(statusStore.read().state).toBe('up');
            supervisorGateway.setProbeResult({ state: 'down', reason: 'process disappeared' });
            supervisorGateway.setSpawnResult({ state: 'spawned', pid: 67890, reason: null });
            const status = await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => new Date('2026-05-23T08:01:00Z'),
            });
            expect(capturing.warnMessages.some(message => message.includes('down'))).toBe(true);
            expect(supervisorGateway.spawnCallCount).toBe(1);
            expect(status.state).toBe('up');
        });
    });
    describe('Lock guard: prevents duplicate spawns', () => {
        it('does not spawn when the lock is already held by a live owner', async () => {
            supervisorGateway.setProbeResult({ state: 'down', reason: 'exit code 1' });
            lockGateway.setAcquireResult({ acquired: false, reason: 'lock held by another process' });
            const status = await checkSupervisorAndRespawn({
                supervisorGateway,
                lockGateway,
                statusStore,
                logger: capturing.logger,
                now: () => fixedNow,
            });
            expect(supervisorGateway.spawnCallCount).toBe(0);
            expect(status.state).toBe('down');
        });
    });
});
//# sourceMappingURL=172-claude-agents-supervisor-lifecycle.acceptance.test.js.map