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

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

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

const createUser = async (t: ReturnType<typeof convexTest>, email: string) =>
  await t.mutation(async (ctx) => {
    return await ctx.db.insert('users', { email, name: email });
  });

const authed = (t: ReturnType<typeof convexTest>, userId: string) =>
  t.withIdentity({
    subject: `${userId}|session`,
    issuer: 'https://convex.test',
  });

const spoonInput = {
  name: 'Editor Spoon',
  provider: 'gitea' as const,
  upstreamOwner: 'upstream',
  upstreamRepo: 'editor',
  upstreamDefaultBranch: 'main',
  upstreamUrl: 'https://git.example.com/upstream/editor',
  forkOwner: 'team',
  forkRepo: 'editor-spoon',
  forkUrl: 'https://git.example.com/team/editor-spoon',
  visibility: 'private' as const,
  maintenanceMode: 'watch' as const,
  syncCadence: 'daily' as const,
  productionRefStrategy: 'default_branch' as const,
};

describe('convex-test harness', () => {
  test('boots and executes against the project schema', async () => {
    const t = convexTest(schema, modules);
    expect(await t.run(() => Promise.resolve(42))).toBe(42);
  });

  test('requires authentication to create a Spoon', async () => {
    const t = convexTest(schema, modules);
    await expect(
      t.mutation(api.spoons.createManual, spoonInput),
    ).rejects.toThrow('Not authenticated.');
  });

  test('creates and lists Spoons for the current user', async () => {
    const t = convexTest(schema, modules);
    const userId = await createUser(t, 'one@example.com');
    const session = authed(t, userId);

    const spoonId = await session.mutation(api.spoons.createManual, spoonInput);
    const spoons = await session.query(api.spoons.listMine, {});

    expect(spoons).toHaveLength(1);
    expect(spoons[0]?._id).toBe(spoonId);
    expect(spoons[0]?.ownerId).toBe(userId);
  });

  test('does not allow reading another user’s Spoon', async () => {
    const t = convexTest(schema, modules);
    const ownerId = await createUser(t, 'owner@example.com');
    const otherId = await createUser(t, 'other@example.com');
    const spoonId = await authed(t, ownerId).mutation(
      api.spoons.createManual,
      spoonInput,
    );

    await expect(
      authed(t, otherId).query(api.spoons.get, { spoonId }),
    ).rejects.toThrow('Spoon not found.');
  });

  test('requires Spoon ownership for agent requests', async () => {
    const t = convexTest(schema, modules);
    const ownerId = await createUser(t, 'owner@example.com');
    const otherId = await createUser(t, 'other@example.com');
    const spoonId = await authed(t, ownerId).mutation(
      api.spoons.createManual,
      spoonInput,
    );

    await expect(
      authed(t, otherId).mutation(api.agentRequests.create, {
        spoonId,
        prompt: 'Add a settings page',
      }),
    ).rejects.toThrow('Spoon not found.');
  });
});
