import { prisma } from "./db";
import { callbackChecksum, ipayConfigured, ipaySecret, safeEqual, type CallbackPayload } from "./ipay";
import { amountsEqual } from "./money";
import { deliverWebhook } from "./webhook";

export type CallbackResult = { status: number; body: { ok: boolean; error?: string } };

function paymentStatusFor(ipayStatus: string): "PAID" | "FAILED" | null {
  if (ipayStatus === "A" || ipayStatus === "P") return "PAID";
  if (ipayStatus === "D") return "FAILED";
  return null;
}

export async function handleIpayCallback(payload: CallbackPayload): Promise<CallbackResult> {
  if (!ipayConfigured()) {
    return { status: 503, body: { ok: false, error: "iPay is not configured" } };
  }
  if (!payload.orderId || !payload.checksum || !payload.transactionStatus) {
    return { status: 400, body: { ok: false, error: "Missing callback fields" } };
  }

  const expected = callbackChecksum(ipaySecret(), payload);
  if (!safeEqual(expected, payload.checksum)) {
    console.warn(`[ipay] invalid checksum order=${payload.orderId}`);
    return { status: 400, body: { ok: false, error: "Invalid checksum" } };
  }

  const payment = await prisma.payment.findUnique({ where: { orderId: payload.orderId } });
  if (!payment) {
    return { status: 400, body: { ok: false, error: "Unknown order" } };
  }
  if (!amountsEqual(payment.amount, payload.transactionAmount)) {
    console.error(
      `[ipay] amount mismatch order=${payload.orderId} stored=${payment.amount} received=${payload.transactionAmount}`
    );
    return { status: 400, body: { ok: false, error: "Amount mismatch" } };
  }

  const nextStatus = paymentStatusFor(payload.transactionStatus);
  if (!nextStatus) {
    return { status: 400, body: { ok: false, error: "Unknown transaction status" } };
  }

  if (payment.status === "PAID" || payment.status === "FAILED") {
    if (payment.ipayStatus && payment.ipayStatus !== payload.transactionStatus) {
      console.warn(
        `[ipay] ignoring new status order=${payment.orderId} stored=${payment.ipayStatus} received=${payload.transactionStatus}`
      );
    }
    if (!payment.webhookSentAt) await deliverWebhook(payment.id);
    return { status: 200, body: { ok: true } };
  }

  const updated = await prisma.payment.updateMany({
    where: { id: payment.id, status: { in: ["PENDING", "CANCELLED"] } },
    data: {
      status: nextStatus,
      ipayStatus: payload.transactionStatus,
      ipayReference: payload.transactionReference || null,
      ipayMessage: payload.transactionMessage ? payload.transactionMessage.slice(0, 200) : null,
    },
  });

  if (updated.count === 0) {
    const fresh = await prisma.payment.findUnique({ where: { id: payment.id } });
    if (fresh && !fresh.webhookSentAt && (fresh.status === "PAID" || fresh.status === "FAILED")) {
      await deliverWebhook(fresh.id);
    }
    return { status: 200, body: { ok: true } };
  }

  console.log(`[ipay] order=${payload.orderId} ipay=${payload.transactionStatus} hub=${nextStatus}`);
  await deliverWebhook(payment.id);
  return { status: 200, body: { ok: true } };
}
