import { mkdtemp, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { describe, expect, it, vi } from 'vitest';
import { FileQueueStore } from './file-store.js';
import { MemoryQueueStore } from './memory-store.js';
import { QueueWorker } from './worker.js';

describe('MemoryQueueStore', () => {
  it('enqueues and retrieves jobs', async () => {
    const store = new MemoryQueueStore();
    const job = await store.enqueue('test', {
      type: 'demo',
      payload: { value: 1 },
    });

    const found = await store.get('test', job.id);
    expect(found?.payload).toEqual({ value: 1 });
    expect(found?.status).toBe('queued');
  });
});

describe('FileQueueStore', () => {
  it('persists jobs across store instances', async () => {
    const dir = await mkdtemp(join(tmpdir(), 'queue-store-'));
    const filePath = join(dir, 'jobs.json');

    const first = new FileQueueStore({ filePath });
    const job = await first.enqueue('persisted', {
      type: 'demo',
      payload: { ok: true },
    });

    const second = new FileQueueStore({ filePath });
    const found = await second.get('persisted', job.id);
    expect(found?.payload).toEqual({ ok: true });

    const raw = JSON.parse(await readFile(filePath, 'utf-8')) as Record<
      string,
      Array<{ id: string }>
    >;
    expect(raw.persisted[0].id).toBe(job.id);
  });
});

describe('QueueWorker', () => {
  it('processes queued jobs to completion', async () => {
    const store = new MemoryQueueStore();
    const worker = new QueueWorker<{ value: number }, { doubled: number }>({
      queueName: 'work',
      store,
      pollIntervalMs: 5,
      handler: async job => ({ doubled: job.payload.value * 2 }),
    });

    worker.start();
    const job = await store.enqueue('work', {
      type: 'double',
      payload: { value: 21 },
    });

    await vi.waitFor(async () => {
      const updated = await store.get<{ value: number }, { doubled: number }>('work', job.id);
      expect(updated?.status).toBe('succeeded');
      expect(updated?.result).toEqual({ doubled: 42 });
    });

    await worker.stop();
  });
});
