import { convexTest } from 'convex-test';
import { describe, expect, test } from 'vitest';

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

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

describe('migrateOpenAiDirectRuntime', () => {
  test('rewrites legacy openai_direct rows to opencode and leaves others', async () => {
    const t = convexTest(schema, modules);
    const now = Date.now();

    const ids = await t.run(async (ctx) => {
      const ownerId = await ctx.db.insert('users', {
        email: 'owner@example.com',
        name: 'Owner',
      });
      const spoonId = await ctx.db.insert('spoons', {
        ownerId,
        name: 'legacy-spoon',
        provider: 'gitea',
        upstreamOwner: 'upstream',
        upstreamRepo: 'legacy-spoon',
        upstreamDefaultBranch: 'main',
        upstreamUrl: 'https://example.com/upstream/legacy-spoon',
        forkOwner: 'owner',
        forkRepo: 'legacy-spoon',
        forkUrl: 'https://example.com/owner/legacy-spoon',
        visibility: 'private',
        maintenanceMode: 'watch',
        syncCadence: 'daily',
        productionRefStrategy: 'default_branch',
        status: 'active',
        createdAt: now,
        updatedAt: now,
      });
      const agentRequestId = await ctx.db.insert('agentRequests', {
        spoonId,
        ownerId,
        prompt: 'legacy request',
        status: 'running',
        createdAt: now,
        updatedAt: now,
      });

      const settings = (runtime: 'openai_direct' | 'codex') => ({
        spoonId,
        ownerId,
        enabled: true,
        runtime,
        branchPrefix: 'spoon/',
        agentModel: 'gpt-5',
        reasoningEffort: 'medium' as const,
        maxJobDurationMs: 600000,
        maxOutputBytes: 1000000,
        createdAt: now,
        updatedAt: now,
      });
      const job = (runtime: 'openai_direct' | 'codex') => ({
        spoonId,
        ownerId,
        agentRequestId,
        status: 'running' as const,
        prompt: 'legacy job',
        runtime,
        baseBranch: 'main',
        workBranch: 'spoon/legacy',
        forkOwner: 'owner',
        forkRepo: 'legacy-spoon',
        forkUrl: 'https://example.com/owner/legacy-spoon',
        upstreamOwner: 'upstream',
        upstreamRepo: 'legacy-spoon',
        selectedSecretIds: [],
        model: 'gpt-5',
        reasoningEffort: 'medium' as const,
        createdAt: now,
        updatedAt: now,
      });

      return {
        legacySettings: await ctx.db.insert(
          'spoonAgentSettings',
          settings('openai_direct'),
        ),
        legacyJob: await ctx.db.insert('agentJobs', job('openai_direct')),
        codexSettings: await ctx.db.insert(
          'spoonAgentSettings',
          settings('codex'),
        ),
        codexJob: await ctx.db.insert('agentJobs', job('codex')),
      };
    });

    const result = await t.mutation(
      internal.migrations.migrateOpenAiDirectRuntime,
      {},
    );

    expect(result.patched).toBe(2);

    const after = await t.run(async (ctx) => ({
      legacySettings: await ctx.db.get(ids.legacySettings),
      legacyJob: await ctx.db.get(ids.legacyJob),
      codexSettings: await ctx.db.get(ids.codexSettings),
      codexJob: await ctx.db.get(ids.codexJob),
    }));

    expect(after.legacySettings?.runtime).toBe('opencode');
    expect(after.legacyJob?.runtime).toBe('opencode');
    expect(after.codexSettings?.runtime).toBe('codex');
    expect(after.codexJob?.runtime).toBe('codex');
  });
});
