import { z } from "zod";
import { createTRPCRouter, adminProcedure } from "../trpc.js";
import { createAuditEntry } from "../lib/audit.js";
import {
  buildWebhookCreateData,
  buildWebhookUpdateData,
  createWebhookInputSchema,
  loadWebhookOrThrow,
  sendWebhookTestRequest,
  updateWebhookInputSchema,
} from "./webhook-support.js";

export const webhookRouter = createTRPCRouter({
  /** List all webhooks. */
  list: adminProcedure.query(async ({ ctx }) => {
    return ctx.db.webhook.findMany({
      orderBy: { createdAt: "desc" },
    });
  }),

  /** Get a single webhook by ID. */
  getById: adminProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => loadWebhookOrThrow(ctx.db, input.id)),

  /** Create a new webhook. */
  create: adminProcedure
    .input(createWebhookInputSchema)
    .mutation(async ({ ctx, input }) => {
      const webhook = await ctx.db.webhook.create({
        data: buildWebhookCreateData(input),
      });

      void createAuditEntry({
        db: ctx.db,
        entityType: "Webhook",
        entityId: webhook.id,
        entityName: webhook.name,
        action: "CREATE",
        userId: ctx.dbUser?.id,
        after: webhook as unknown as Record<string, unknown>,
        source: "ui",
      });

      return webhook;
    }),

  /** Update an existing webhook. */
  update: adminProcedure
    .input(
      z.object({
        id: z.string(),
        data: updateWebhookInputSchema,
      }),
    )
    .mutation(async ({ ctx, input }) => {
      const existing = await loadWebhookOrThrow(ctx.db, input.id);

      const updated = await ctx.db.webhook.update({
        where: { id: input.id },
        data: buildWebhookUpdateData(input.data),
      });

      void createAuditEntry({
        db: ctx.db,
        entityType: "Webhook",
        entityId: input.id,
        entityName: updated.name,
        action: "UPDATE",
        userId: ctx.dbUser?.id,
        before: existing as unknown as Record<string, unknown>,
        after: updated as unknown as Record<string, unknown>,
        source: "ui",
      });

      return updated;
    }),

  /** Delete a webhook. */
  delete: adminProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const existing = await loadWebhookOrThrow(ctx.db, input.id);
      await ctx.db.webhook.delete({ where: { id: input.id } });

      void createAuditEntry({
        db: ctx.db,
        entityType: "Webhook",
        entityId: input.id,
        entityName: existing.name,
        action: "DELETE",
        userId: ctx.dbUser?.id,
        before: existing as unknown as Record<string, unknown>,
        source: "ui",
      });
    }),

  /** Send a test payload to a webhook URL. */
  test: adminProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const wh = await loadWebhookOrThrow(ctx.db, input.id);
      const result = await sendWebhookTestRequest(wh);

      void createAuditEntry({
        db: ctx.db,
        entityType: "Webhook",
        entityId: wh.id,
        entityName: wh.name,
        action: "UPDATE",
        userId: ctx.dbUser?.id,
        summary: `Tested webhook (result: ${result.success ? "success" : "failed"})`,
        metadata: result as unknown as Record<string, unknown>,
        source: "ui",
      });

      return result;
    }),
});
