/**
 * Zod schemas for payment API routes and webhook bodies.
 *
 * Used at the API boundary for input validation.
 */

import { z } from 'zod';

// ---------------------------------------------------------------------------
// Shared primitives
// ---------------------------------------------------------------------------

const uuidSchema = z.uuid('Must be a valid UUID');
const amountStringSchema = z
  .string()
  .trim()
  .regex(/^\d+(\.\d{1,2})?$/, 'Amount must be a positive decimal string (e.g. "49.90")');

// ---------------------------------------------------------------------------
// Morning webhook body
// ---------------------------------------------------------------------------

/**
 * Shape of an incoming Morning webhook event.
 *
 * Morning sends events as JSON with at least:
 *   { id, type, createdAt, data: { ... } }
 *
 * Field names match Morning's documented webhook schema (all fields optional
 * since Morning may omit fields depending on event type).
 */
export const morningWebhookDataSchema = z.object({
  /** The primary resource ID (charge ID, refund ID, etc.) */
  id: z.string().optional(),
  /** For refund events: the original charge ID */
  chargeId: z.string().optional(),
  originalChargeId: z.string().optional(),
  /** For refund events: the refund ID */
  refundId: z.string().optional(),
  /** Amount in ILS (numeric) */
  amount: z.number().optional(),
  currency: z.string().optional(),
  /** ISO 8601 timestamp */
  createdAt: z.string().optional(),
  /** Associated document (invoice) ID */
  documentId: z.string().optional(),
});

export type MorningWebhookData = z.infer<typeof morningWebhookDataSchema>;

export const morningWebhookBodySchema = z.object({
  /** Unique event ID from Morning */
  id: z.string().min(1),
  /**
   * Event type string from Morning. Accepted as a freeform string to remain
   * forward-compatible as Morning adds new event types. Handlers switch on
   * the value at runtime (charge.succeeded, refund.succeeded, etc.).
   */
  type: z.string().min(1),
  /** ISO 8601 creation timestamp */
  createdAt: z.string().optional(),
  /** Event payload - shape depends on event type */
  data: morningWebhookDataSchema.optional().default({}),
});

export type MorningWebhookBody = z.infer<typeof morningWebhookBodySchema>;

// ---------------------------------------------------------------------------
// POST /api/payments/tokenize - initiate hosted payment form
// ---------------------------------------------------------------------------

export const tokenizeRequestSchema = z.object({
  /** CSRF token */
  csrfToken: z.string().min(1).optional(),
});

export type TokenizeRequest = z.infer<typeof tokenizeRequestSchema>;

export const tokenizeResponseSchema = z.object({
  ok: z.literal(true),
  token: z.string(),
  last4: z.string(),
  brand: z.string(),
});

export type TokenizeResponse = z.infer<typeof tokenizeResponseSchema>;

// ---------------------------------------------------------------------------
// POST /api/payments/charge - explicit charge request (if used directly)
// ---------------------------------------------------------------------------

export const chargeRequestSchema = z.object({
  paymentToken: z.string().min(1).max(512),
  amount: amountStringSchema,
  idempotencyKey: z.string().min(8).max(128),
  description: z.string().trim().min(1).max(500).optional(),
  csrfToken: z.string().min(1).optional(),
});

export type ChargeRequest = z.infer<typeof chargeRequestSchema>;

export const chargeResponseSchema = z.object({
  ok: z.literal(true),
  chargeId: z.string(),
});

export type ChargeResponse = z.infer<typeof chargeResponseSchema>;

// ---------------------------------------------------------------------------
// POST /api/payments/refund - explicit refund request
// ---------------------------------------------------------------------------

export const refundRequestSchema = z.object({
  purchaseId: uuidSchema,
  /** Override amount - defaults to calculated refund amount if omitted */
  amount: amountStringSchema.optional(),
  csrfToken: z.string().min(1).optional(),
});

export type RefundRequest = z.infer<typeof refundRequestSchema>;

export const refundResponseSchema = z.object({
  ok: z.literal(true),
  refundId: z.string(),
  purchaseId: uuidSchema,
  amount: amountStringSchema,
});

export type RefundResponse = z.infer<typeof refundResponseSchema>;

// ---------------------------------------------------------------------------
// POST /api/payments/invoice - issue invoice for a purchase
// ---------------------------------------------------------------------------

export const issueInvoiceRequestSchema = z.object({
  purchaseId: uuidSchema,
  csrfToken: z.string().min(1).optional(),
});

export type IssueInvoiceRequest = z.infer<typeof issueInvoiceRequestSchema>;

export const issueInvoiceResponseSchema = z.object({
  ok: z.literal(true),
  invoiceId: z.string(),
  documentUrl: z.url(),
  documentNumber: z.string(),
});

export type IssueInvoiceResponse = z.infer<typeof issueInvoiceResponseSchema>;
