import { describe, it, expect, beforeEach } from 'vitest';
import { promises as fs } from 'fs';
import path from 'path';
import { SequentialOrchestrator } from '../services/SequentialOrchestrator.js';
import { WorkflowStatusManager, type WorkflowStatus } from '../services/WorkflowStatusManager.js';

const tempCheckpoint = path.join(process.cwd(), 'data/test-orch-checkpoint-status.json');
const tempStatus = path.join(process.cwd(), 'status/test-workflow-status-status.json');

async function cleanFiles() {
  try { await fs.unlink(tempCheckpoint); } catch {}
  try { await fs.unlink(tempStatus); } catch {}
  await fs.mkdir(path.dirname(tempStatus), { recursive: true });
}

describe('SequentialOrchestrator + WorkflowStatusManager', () => {
  beforeEach(async () => { await cleanFiles(); });

  it('writes correct status for each phase boundary (success)', async () => {
    const calls: string[] = [];
    const orchestrator = new SequentialOrchestrator({
      phases: [
        { name: 'phase1', run: async () => { calls.push('1'); }, nextAction: 'next1' },
        { name: 'phase2', run: async () => { calls.push('2'); }, nextAction: 'next2' },
      ],
      checkpointPath: tempCheckpoint,
      input: undefined,
      statusFilePath: tempStatus,
    });
    await orchestrator.run();
    const statusMgr = new WorkflowStatusManager(tempStatus);
    const status: WorkflowStatus | null = await statusMgr.read();
    expect(status).not.toBeNull();
    expect(status!.overallStatus).toBe('completed');
    expect(status!.currentPhase).toBeNull();
    expect(status!.completedPhases).toEqual(['phase1','phase2']);
    expect(status!.lastFailureReason).toBeNull();
    expect(status!.nextAction).toBe('done');
  });

  it('writes correct status for failed phase and retry', async () => {
    const orchestrator = new SequentialOrchestrator({
      phases: [
        { name: 'phase1', run: async () => { throw new Error('nope'); }, retry: 2, nextAction: 'next1' },
      ],
      checkpointPath: tempCheckpoint,
      input: undefined,
      statusFilePath: tempStatus,
    });
    await orchestrator.run();
    const statusMgr = new WorkflowStatusManager(tempStatus);
    const status: WorkflowStatus | null = await statusMgr.read();
    expect(status).not.toBeNull();
    expect(status!.overallStatus).toBe('failed');
    expect(status!.currentPhase).toBe('phase1');
    expect(status!.completedPhases).toEqual([]);
    expect((status!.lastFailureReason||'')+ '').toMatch('nope');
  });

  it('status is atomic (no corruption)', async () => {
    const orchestrator = new SequentialOrchestrator({
      phases: [
        { name: 'p1', run: async () => {} },
      ],
      checkpointPath: tempCheckpoint,
      input: undefined,
      statusFilePath: tempStatus,
    });
    await orchestrator.run();
    // Try reading incomplete file (simulate crash in middle of write)
    const statusMgr = new WorkflowStatusManager(tempStatus);
    const txt = await fs.readFile(tempStatus, 'utf8');
    expect(() => JSON.parse(txt)).not.toThrow();
    const stat = await statusMgr.read();
    expect(stat).not.toBeNull();
    expect(stat!.overallStatus).toBe('completed');
  });
});
