import { randomUUID } from "node:crypto";
import {
  PaymentEvent,
  PaymentFailedEvent,
  PaymentSucceededEvent,
} from "@edr/types";
import { PaymentIntent } from "../intents/entities/payment-intent.entity";
import { NotificationOutbox } from "./entities/notification-outbox.entity";

/**
 * Build a ready-to-insert outbox row for a terminal intent. Pure (no DI) so the intents
 * state machine can insert it inside its own DB transaction without a module cycle.
 * The row id is generated here because the event envelope embeds it as `eventId`.
 */
export function buildOutboxRow(
  intent: PaymentIntent,
  terminal:
    | { eventType: "payment.succeeded"; providerTxnId?: string; paidAt: Date }
    | {
        eventType: "payment.failed";
        failureCode?: string;
        failureMessage?: string;
      },
): Partial<NotificationOutbox> {
  const id = randomUUID();
  const base = {
    version: 1 as const,
    eventId: id,
    occurredAt: new Date().toISOString(),
    service: intent.service,
    intentId: intent.id,
    referenceType: intent.referenceType,
    referenceId: intent.referenceId,
    merchantOrderId: intent.merchantOrderId,
    provider: intent.provider,
    amountMinor: intent.amountMinor,
    currency: intent.currency,
  };

  const event: PaymentEvent =
    terminal.eventType === "payment.succeeded"
      ? ({
          ...base,
          eventType: "payment.succeeded",
          providerTxnId: terminal.providerTxnId,
          paidAt: terminal.paidAt.toISOString(),
        } satisfies PaymentSucceededEvent)
      : ({
          ...base,
          eventType: "payment.failed",
          failureCode: terminal.failureCode,
          failureMessage: terminal.failureMessage,
        } satisfies PaymentFailedEvent);

  return {
    id,
    eventType: event.eventType,
    service: intent.service,
    intentId: intent.id,
    referenceType: intent.referenceType,
    referenceId: intent.referenceId,
    payload: event,
    status: "PENDING",
    attempts: 0,
  };
}
