import { describe, it, expect, beforeEach } from 'vitest';
import { pauseQueue } from '../src/proxymodel/pause-queue.js';

beforeEach(() => {
  // Reset state between tests
  pauseQueue.setPaused(false);
});

describe('PauseQueue', () => {
  it('returns transformed content immediately when not paused', async () => {
    const result = await pauseQueue.enqueue({
      sessionId: 's1',
      projectName: 'proj',
      contentType: 'toolResult',
      sourceName: 'test/tool',
      original: 'raw content',
      transformed: 'processed content',
    });
    expect(result).toBe('processed content');
    expect(pauseQueue.size).toBe(0);
  });

  it('holds content when paused', async () => {
    pauseQueue.setPaused(true);

    let resolved = false;
    const promise = pauseQueue.enqueue({
      sessionId: 's1',
      projectName: 'proj',
      contentType: 'toolResult',
      sourceName: 'test/tool',
      original: 'raw',
      transformed: 'processed',
    }).then((r) => { resolved = true; return r; });

    // Should not resolve immediately
    await new Promise((r) => setTimeout(r, 50));
    expect(resolved).toBe(false);
    expect(pauseQueue.size).toBe(1);

    // Release it
    const items = pauseQueue.getItems();
    expect(items).toHaveLength(1);
    pauseQueue.releaseOne(items[0]!.id);

    const result = await promise;
    expect(result).toBe('processed');
    expect(resolved).toBe(true);
    expect(pauseQueue.size).toBe(0);
  });

  it('editAndRelease sends edited content', async () => {
    pauseQueue.setPaused(true);

    const promise = pauseQueue.enqueue({
      sessionId: 's1',
      projectName: 'proj',
      contentType: 'toolResult',
      sourceName: 'test/tool',
      original: 'raw',
      transformed: 'auto-processed',
    });

    const items = pauseQueue.getItems();
    pauseQueue.editAndRelease(items[0]!.id, 'manually-edited');

    const result = await promise;
    expect(result).toBe('manually-edited');
  });

  it('dropOne sends empty content', async () => {
    pauseQueue.setPaused(true);

    const promise = pauseQueue.enqueue({
      sessionId: 's1',
      projectName: 'proj',
      contentType: 'toolResult',
      sourceName: 'test/tool',
      original: 'raw',
      transformed: 'processed',
    });

    const items = pauseQueue.getItems();
    pauseQueue.dropOne(items[0]!.id);

    const result = await promise;
    expect(result).toBe('');
  });

  it('setPaused(false) releases all queued items', async () => {
    pauseQueue.setPaused(true);

    const p1 = pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool1', original: 'r1', transformed: 't1',
    });
    const p2 = pauseQueue.enqueue({
      sessionId: 's2', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool2', original: 'r2', transformed: 't2',
    });

    expect(pauseQueue.size).toBe(2);

    // Resume releases all
    pauseQueue.setPaused(false);

    const [r1, r2] = await Promise.all([p1, p2]);
    expect(r1).toBe('t1');
    expect(r2).toBe('t2');
    expect(pauseQueue.size).toBe(0);
  });

  it('releaseAll releases all items and returns count', async () => {
    pauseQueue.setPaused(true);

    const p1 = pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool1', original: 'r1', transformed: 't1',
    });
    const p2 = pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool2', original: 'r2', transformed: 't2',
    });

    const count = pauseQueue.releaseAll();
    expect(count).toBe(2);

    const [r1, r2] = await Promise.all([p1, p2]);
    expect(r1).toBe('t1');
    expect(r2).toBe('t2');
  });

  it('returns false for operations on non-existent IDs', () => {
    expect(pauseQueue.releaseOne('nonexistent')).toBe(false);
    expect(pauseQueue.editAndRelease('nonexistent', 'x')).toBe(false);
    expect(pauseQueue.dropOne('nonexistent')).toBe(false);
  });

  it('getItems strips internal resolve function', async () => {
    pauseQueue.setPaused(true);

    pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool', original: 'raw', transformed: 'processed',
    });

    const items = pauseQueue.getItems();
    expect(items).toHaveLength(1);
    const item = items[0]!;
    expect(item.id).toBeTruthy();
    expect(item.sessionId).toBe('s1');
    expect(item.projectName).toBe('proj');
    expect(item.contentType).toBe('toolResult');
    expect(item.sourceName).toBe('tool');
    expect(item.original).toBe('raw');
    expect(item.transformed).toBe('processed');
    expect(item.timestamp).toBeGreaterThan(0);
    // Must not expose resolve
    expect((item as Record<string, unknown>)['resolve']).toBeUndefined();

    // Cleanup
    pauseQueue.releaseAll();
  });

  it('notifies subscribers on enqueue and release', async () => {
    const notifications: number[] = [];
    const unsub = pauseQueue.subscribe((items) => notifications.push(items.length));

    pauseQueue.setPaused(true);

    pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool', original: 'r', transformed: 't',
    });

    expect(notifications).toContain(1);

    pauseQueue.releaseAll();
    expect(notifications).toContain(0);

    unsub();
  });

  it('each item gets a unique ID', async () => {
    pauseQueue.setPaused(true);

    pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool1', original: 'r1', transformed: 't1',
    });
    pauseQueue.enqueue({
      sessionId: 's1', projectName: 'proj', contentType: 'toolResult',
      sourceName: 'tool2', original: 'r2', transformed: 't2',
    });

    const items = pauseQueue.getItems();
    expect(items).toHaveLength(2);
    expect(items[0]!.id).not.toBe(items[1]!.id);

    pauseQueue.releaseAll();
  });
});
