import { v } from 'convex/values';

import { internalMutation, query } from './_generated/server';
import { getOwnedSpoon, getRequiredUserId } from './model';

const scope = v.union(
  v.literal('fork'),
  v.literal('upstream'),
  v.literal('from_fork_to_upstream'),
);

const state = v.union(
  v.literal('open'),
  v.literal('closed'),
  v.literal('merged'),
);

export const listForSpoon = query({
  args: {
    spoonId: v.id('spoons'),
    scope: v.optional(scope),
    state: v.optional(state),
    limit: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    const ownerId = await getRequiredUserId(ctx);
    await getOwnedSpoon(ctx, args.spoonId, ownerId);
    const requestedScope = args.scope;
    const rows = requestedScope
      ? await ctx.db
          .query('spoonPullRequests')
          .withIndex('by_spoon_scope', (q) =>
            q.eq('spoonId', args.spoonId).eq('scope', requestedScope),
          )
          .order('desc')
          .collect()
      : await ctx.db
          .query('spoonPullRequests')
          .withIndex('by_spoon', (q) => q.eq('spoonId', args.spoonId))
          .order('desc')
          .collect();
    return rows
      .filter((row) => !args.state || row.state === args.state)
      .slice(0, args.limit ?? 100);
  },
});

export const replaceForSpoon = internalMutation({
  args: {
    spoonId: v.id('spoons'),
    ownerId: v.id('users'),
    scope,
    pullRequests: v.array(
      v.object({
        githubId: v.number(),
        number: v.number(),
        repoFullName: v.string(),
        title: v.string(),
        state,
        draft: v.boolean(),
        authorLogin: v.optional(v.string()),
        baseRef: v.string(),
        headRef: v.string(),
        headRepoFullName: v.optional(v.string()),
        htmlUrl: v.string(),
        createdAtGithub: v.optional(v.number()),
        updatedAtGithub: v.optional(v.number()),
        mergedAtGithub: v.optional(v.number()),
      }),
    ),
  },
  handler: async (ctx, { spoonId, ownerId, scope, pullRequests }) => {
    const existing = await ctx.db
      .query('spoonPullRequests')
      .withIndex('by_spoon_scope', (q) =>
        q.eq('spoonId', spoonId).eq('scope', scope),
      )
      .collect();
    await Promise.all(
      existing.map((pullRequest) => ctx.db.delete(pullRequest._id)),
    );
    const now = Date.now();
    await Promise.all(
      pullRequests.map((pullRequest) =>
        ctx.db.insert('spoonPullRequests', {
          spoonId,
          ownerId,
          scope,
          ...pullRequest,
          createdAt: now,
          updatedAt: now,
        }),
      ),
    );
    return { success: true };
  },
});
