import { convexTest } from 'convex-test';
import { ConvexError } from 'convex/values';
import { afterEach, describe, expect, test } from 'vitest';

import { internal } from '../../convex/_generated/api.js';
import schema from '../../convex/schema';
import { assertWorkerToken } from '../../convex/workerAuth';

const modules = import.meta.glob('../../convex/**/*.*s');

afterEach(() => {
  delete process.env.SPOON_WORKER_TOKEN;
});

describe('assertWorkerToken', () => {
  test('accepts a token that matches after trimming', () => {
    process.env.SPOON_WORKER_TOKEN = 'secret\n';
    expect(() => assertWorkerToken('secret')).not.toThrow();
    expect(() => assertWorkerToken(' secret ')).not.toThrow();
  });

  test('rejects a mismatched token', () => {
    process.env.SPOON_WORKER_TOKEN = 'secret';
    expect(() => assertWorkerToken('nope')).toThrow(ConvexError);
  });

  test('throws when not configured', () => {
    expect(() => assertWorkerToken('x')).toThrow(ConvexError);
  });
});

describe('getRawEnvironmentForJobInternal', () => {
  test('only exposes environment for a claimed job', async () => {
    const t = convexTest(schema, modules);
    const jobId = await t.mutation(async (ctx) => {
      const now = Date.now();
      const ownerId = await ctx.db.insert('users', {
        email: 'worker-auth@example.com',
        name: 'Worker Auth',
      });
      const spoonId = await ctx.db.insert('spoons', {
        ownerId,
        name: 'Worker Auth Spoon',
        provider: 'gitea',
        upstreamOwner: 'upstream',
        upstreamRepo: 'worker-auth',
        upstreamDefaultBranch: 'main',
        upstreamUrl: 'https://git.example.com/upstream/worker-auth',
        forkOwner: 'team',
        forkRepo: 'worker-auth-spoon',
        forkUrl: 'https://git.example.com/team/worker-auth-spoon',
        visibility: 'private',
        maintenanceMode: 'watch',
        syncCadence: 'daily',
        productionRefStrategy: 'default_branch',
        status: 'active',
        createdAt: now,
        updatedAt: now,
      });
      const requestId = await ctx.db.insert('agentRequests', {
        spoonId,
        ownerId,
        prompt: 'Test worker authorization',
        status: 'queued',
        createdAt: now,
        updatedAt: now,
      });
      return await ctx.db.insert('agentJobs', {
        spoonId,
        ownerId,
        agentRequestId: requestId,
        status: 'queued',
        prompt: 'Test worker authorization',
        runtime: 'opencode',
        baseBranch: 'main',
        workBranch: 'spoon/worker-auth',
        forkOwner: 'team',
        forkRepo: 'worker-auth-spoon',
        forkUrl: 'https://git.example.com/team/worker-auth-spoon',
        upstreamOwner: 'upstream',
        upstreamRepo: 'worker-auth',
        selectedSecretIds: [],
        model: '',
        reasoningEffort: 'medium',
        createdAt: now,
        updatedAt: now,
      });
    });

    expect(
      await t.query(internal.userEnvironment.getRawEnvironmentForJobInternal, {
        jobId,
      }),
    ).toBeNull();

    await t.mutation(async (ctx) => {
      await ctx.db.patch(jobId, { claimedBy: 'w1' });
    });

    expect(
      await t.query(internal.userEnvironment.getRawEnvironmentForJobInternal, {
        jobId,
      }),
    ).not.toBeNull();
  });
});
