import { v } from 'convex/values';

import { mutation } from '../../_generated/server';
import { validateAgentName } from '../../agents/validators';
import { getAuthUserIdentity } from '../../lib/rls/auth/get_auth_user_identity';
import { getOrganizationMember } from '../../lib/rls/organization/get_organization_member';
import { generateToken } from '../../workflows/triggers/helpers/crypto';

export const createWebhook = mutation({
  args: {
    organizationId: v.string(),
    agentSlug: v.string(),
  },
  returns: v.object({
    webhookId: v.id('agentWebhooks'),
    token: v.string(),
  }),
  handler: async (ctx, args) => {
    const authUser = await getAuthUserIdentity(ctx);
    if (!authUser) throw new Error('Unauthenticated');

    await getOrganizationMember(ctx, args.organizationId, authUser);

    if (!validateAgentName(args.agentSlug)) {
      throw new Error(`Invalid agent slug: ${args.agentSlug}`);
    }

    const token = generateToken();

    const webhookId = await ctx.db.insert('agentWebhooks', {
      organizationId: args.organizationId,
      agentSlug: args.agentSlug,
      token,
      isActive: true,
      createdAt: Date.now(),
      createdBy: authUser.email ?? authUser.userId,
      createdByUserId: authUser.userId,
    });

    return { webhookId, token };
  },
});

export const toggleWebhook = mutation({
  args: {
    webhookId: v.id('agentWebhooks'),
    isActive: v.boolean(),
  },
  returns: v.null(),
  handler: async (ctx, args) => {
    const authUser = await getAuthUserIdentity(ctx);
    if (!authUser) throw new Error('Unauthenticated');

    const webhook = await ctx.db.get(args.webhookId);
    if (!webhook) throw new Error('Webhook not found');

    await getOrganizationMember(ctx, webhook.organizationId, authUser);

    await ctx.db.patch(args.webhookId, { isActive: args.isActive });
    return null;
  },
});

export const deleteWebhook = mutation({
  args: { webhookId: v.id('agentWebhooks') },
  returns: v.null(),
  handler: async (ctx, args) => {
    const authUser = await getAuthUserIdentity(ctx);
    if (!authUser) throw new Error('Unauthenticated');

    const webhook = await ctx.db.get(args.webhookId);
    if (!webhook) throw new Error('Webhook not found');

    await getOrganizationMember(ctx, webhook.organizationId, authUser);

    // Cascade: remove any user→thread mapping rows for this webhook so the
    // table doesn't accumulate orphans referencing a deleted webhookId.
    const mappings = await ctx.db
      .query('agentWebhookUserThreads')
      .withIndex('by_webhookId_userHash', (q) =>
        q.eq('webhookId', args.webhookId),
      )
      .collect();
    for (const row of mappings) {
      await ctx.db.delete(row._id);
    }

    await ctx.db.delete(args.webhookId);
    return null;
  },
});
