import { prisma } from "./db";
import { webhookSignature } from "./ipay";
import { findProduct } from "./products";
import { asRecord } from "./present";

function clip(err: unknown): string {
  const message = err instanceof Error ? err.message : String(err);
  return message.slice(0, 500);
}

export async function deliverWebhook(paymentId: string): Promise<void> {
  const payment = await prisma.payment.findUnique({ where: { id: paymentId } });
  if (!payment || payment.webhookSentAt) return;
  if (payment.status !== "PAID" && payment.status !== "FAILED") return;

  if (payment.webhookError === "SENDING" && Date.now() - payment.updatedAt.getTime() < 30_000) {
    return;
  }

  const claimed = await prisma.payment.updateMany({
    where: {
      id: payment.id,
      webhookSentAt: null,
      webhookError: payment.webhookError,
    },
    data: { webhookError: "SENDING" },
  });
  if (claimed.count === 0) return;

  const product = findProduct(payment.productId);
  if (!product) {
    await prisma.payment.update({
      where: { id: payment.id },
      data: { webhookError: "Product is no longer in the registry" },
    });
    return;
  }

  const raw = JSON.stringify({
    orderId: payment.orderId,
    productId: payment.productId,
    status: payment.status,
    ipayStatus: payment.ipayStatus,
    amount: payment.amount,
    ipayReference: payment.ipayReference ?? "",
    metadata: asRecord(payment.metadata),
  });
  const signature = webhookSignature(product.apiKey, raw);
  let lastError = "Webhook failed";

  for (let attempt = 1; attempt <= 2; attempt += 1) {
    try {
      const response = await fetch(payment.webhookUrl, {
        method: "POST",
        redirect: "manual",
        headers: {
          "Content-Type": "application/json",
          "User-Agent": "OptimizeSolutions-PaymentHub/1.0",
          "X-Payment-Signature": signature,
        },
        body: raw,
        signal: AbortSignal.timeout(8000),
      });
      if (response.status < 200 || response.status >= 300) {
        throw new Error(`Webhook responded HTTP ${response.status}`);
      }
      await prisma.payment.update({
        where: { id: payment.id },
        data: { webhookSentAt: new Date(), webhookError: null },
      });
      console.log(`[webhook] delivered order=${payment.orderId} product=${payment.productId} attempt=${attempt}`);
      return;
    } catch (err) {
      lastError = clip(err);
      console.error(`[webhook] attempt ${attempt} failed order=${payment.orderId}: ${lastError}`);
    }
  }

  await prisma.payment.update({
    where: { id: payment.id },
    data: { webhookError: lastError },
  });
}
