/**
 * Invoice payment link token helper — invoice-payment-link-generation (wave-12).
 *
 * Signs an HMAC-SHA256 token over `invoiceId:tenantId` using Web Crypto (CF Workers runtime).
 * The resulting base64url token is stateless — validity is derived from invoice status.
 *
 * MUST NOT import from Node 'crypto' — CF Workers use globalThis.crypto (Web Crypto API).
 */

// ── Token signing ─────────────────────────────────────────────────────────────

/**
 * Encode a Uint8Array as base64url (RFC 4648 §5, no padding).
 */
function toBase64Url(buf: ArrayBuffer): string {
  const bytes = new Uint8Array(buf)
  let binary = ''
  for (const b of bytes) {
    binary += String.fromCharCode(b)
  }
  return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
}

/**
 * Derive an HMAC-SHA256 CryptoKey from a raw secret string.
 */
async function importHmacKey(secret: string): Promise<CryptoKey> {
  const keyBytes = new TextEncoder().encode(secret)
  return crypto.subtle.importKey('raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, [
    'sign',
  ])
}

/**
 * Sign an invoice payment token.
 *
 * Token = HMAC-SHA256(key, `{invoiceId}:{tenantId}`) → base64url.
 *
 * @param invoiceId - The invoice UUID
 * @param tenantId  - The tenant UUID
 * @param secret    - The raw INVOICE_PAYMENT_LINK_KEY secret string
 */
export async function signInvoicePaymentToken(
  invoiceId: string,
  tenantId: string,
  secret: string,
): Promise<string> {
  const key = await importHmacKey(secret)
  const message = new TextEncoder().encode(`${invoiceId}:${tenantId}`)
  const sig = await crypto.subtle.sign('HMAC', key, message)
  return toBase64Url(sig)
}

/**
 * Build the full payment link URL for a token.
 *
 * @param token   - The base64url HMAC token from `signInvoicePaymentToken`
 * @param baseUrl - The app base URL (e.g. `https://app.zync.is`). Trailing slash is stripped.
 */
export function buildPaymentLinkUrl(token: string, baseUrl: string): string {
  const base = baseUrl.replace(/\/$/, '')
  return `${base}/pay/${token}`
}
