/**
 * Lossless JSON handling for CAC Bank.
 *
 * CAC returns 17-digit identifiers — `paymentRequestId`, `confirmReference`,
 * `transactionNo` (spec: numeric, <=18) — that exceed `Number.MAX_SAFE_INTEGER`
 * (9,007,199,254,740,991). A plain `JSON.parse` silently rounds them
 * (…240611 → …240610), corrupting the id we send back to CONFIRM the payment and use
 * to VERIFY it via GetPaymentByReferenceRequest. So we quote those fields to strings
 * before parsing and carry them as strings end-to-end, then re-emit id fields as raw
 * JSON numbers when building requests. This avoids a bigint-JSON dependency for the
 * three fields that need it.
 */

/** Response id fields that must survive as exact strings, not JS numbers. */
const RESPONSE_ID_FIELDS = [
  "paymentRequestId",
  "confirmReference",
  "transactionNo",
] as const;

/**
 * Request id fields we carry as strings but the bank types as `numeric`, so they must
 * go on the wire unquoted. Only PaymentConfirmationRequest.payment_request_id qualifies;
 * GetPaymentByReferenceRequest.reference is a string field and stays quoted.
 */
const REQUEST_NUMERIC_ID_FIELDS = ["payment_request_id"] as const;

/**
 * Parse a CAC JSON response body, keeping oversized integer ids as exact strings.
 * `raw` is the untouched response text (axios response transform is disabled for CAC).
 */
export function parseCacResponse<T>(raw: string): T {
  const pattern = new RegExp(
    `"(${RESPONSE_ID_FIELDS.join("|")})"\\s*:\\s*(-?\\d+)`,
    "g",
  );
  const quoted = raw.replace(pattern, '"$1":"$2"');
  return JSON.parse(quoted) as T;
}

/**
 * Serialize a CAC request body. Numeric id fields we hold as strings are emitted as raw
 * JSON numbers (unquoted) so their full precision reaches the bank, matching the spec's
 * `numeric` type. All other fields serialize normally.
 */
export function serializeCacRequest(body: unknown): string {
  let json = JSON.stringify(body);
  for (const field of REQUEST_NUMERIC_ID_FIELDS) {
    json = json.replace(
      new RegExp(`("${field}"\\s*:\\s*)"(-?\\d+)"`, "g"),
      "$1$2",
    );
  }
  return json;
}

/**
 * Normalize a Djibouti mobile number to the bare 8-digit national form the bank expects
 * (spec example `77112233`). Strips a leading `+253` / `00253` / `253` country code and any
 * spaces or dashes. Returns the input trimmed if it doesn't match the expected shape.
 */
export function normalizeCacMobile(mobile: string): string {
  const digits = mobile.replace(/[\s-]/g, "").replace(/^\+/, "");
  const national = digits.replace(/^(?:00)?253/, "");
  return national || digits;
}
