import { describe, expect, it } from 'vitest';

import { isSearchAccountExecutionLocked, withSearchAccountExecutionLock } from './search-account-lock.ts';

function deferred() {
  let resolve!: () => void;
  const promise = new Promise<void>((next) => {
    resolve = next;
  });
  return { promise, resolve };
}

describe('search account execution lock', () => {
  it('runs same-account tasks sequentially', async () => {
    const firstMayFinish = deferred();
    const order: string[] = [];

    const first = withSearchAccountExecutionLock('account-1', async () => {
      order.push('first-start');
      await firstMayFinish.promise;
      order.push('first-finish');
    });
    const second = withSearchAccountExecutionLock('account-1', async () => {
      order.push('second-start');
    });

    await Promise.resolve();
    expect(isSearchAccountExecutionLocked('account-1')).toBe(true);
    expect(order).toEqual(['first-start']);

    firstMayFinish.resolve();
    await Promise.all([first, second]);

    expect(order).toEqual(['first-start', 'first-finish', 'second-start']);
    expect(isSearchAccountExecutionLocked('account-1')).toBe(false);
  });

  it('allows different-account tasks to run independently', async () => {
    const firstMayFinish = deferred();
    const order: string[] = [];

    const first = withSearchAccountExecutionLock('account-1', async () => {
      order.push('first-start');
      await firstMayFinish.promise;
      order.push('first-finish');
    });
    const second = withSearchAccountExecutionLock('account-2', async () => {
      order.push('second-start');
    });

    await second;
    expect(order).toEqual(['first-start', 'second-start']);

    firstMayFinish.resolve();
    await first;
  });
});
