import { describe, it, expect } from 'vitest';
import { runWithInferenceContext, getInferenceContext } from '../inference_context.js';
import type { Sql } from '../../../db.js';

const fakeSql = {} as unknown as Sql;

describe('inference context (AsyncLocalStorage isolation)', () => {
  it('throws when read outside a run', () => {
    expect(() => getInferenceContext()).toThrow(/outside inference context/);
  });

  it('keeps each run its own context across overlapping awaits', async () => {
    // The race the global `let current` had: run B starts (and would overwrite a
    // shared global) while run A is awaiting. After A resumes it must still read
    // its OWN sessionId, not B's.
    const run = (id: string, delay: number) =>
      runWithInferenceContext({ sql: fakeSql, sessionId: id, taskId: null }, async () => {
        await new Promise((r) => setTimeout(r, delay));
        return getInferenceContext().sessionId;
      });

    const [a, b] = await Promise.all([run('A', 20), run('B', 5)]);
    expect(a).toBe('A');
    expect(b).toBe('B');
  });

  it('carries permissionMode and taskId per run', async () => {
    const result = await runWithInferenceContext(
      { sql: fakeSql, sessionId: 's1', taskId: 't1', permissionMode: 'bypass' },
      async () => {
        await Promise.resolve();
        const ctx = getInferenceContext();
        return { taskId: ctx.taskId, mode: ctx.permissionMode };
      },
    );
    expect(result).toEqual({ taskId: 't1', mode: 'bypass' });
  });
});
