/**
 * Immutable receipt HTML snapshot — render + R2 put + persist R2 object key.
 * Mirrors invoice-snapshot.ts; reuses INVOICE_SNAPSHOTS_BUCKET under receipts/ prefix.
 */
import type { Db } from '@zync/db/queries'
import {
  getReceiptWithLines,
  getInvoice,
  setReceiptPdfR2Key,
} from '@zync/db/queries'
import type { ReceiptObject } from '@zync/types'
import type { Env } from '@zync/types'
import { renderReceiptHtml, type ReceiptRenderContext } from '../receipts/render'
import {
  fetchInvoiceHtmlSnapshot,
  loadInvoiceRenderIdentity,
  localeLangSubtag,
} from './invoice-snapshot'

export type ReceiptSnapshotDeps = {
  db: Db
  env: Env
  executionCtx?: { waitUntil(promise: Promise<unknown>): void }
}

function receiptSnapshotR2Key(
  tenantId: string,
  receiptId: string,
  receiptNumber: string,
  lang: string,
): string {
  return `${tenantId}/receipts/${receiptId}/receipt-${receiptNumber}-${lang}.html`
}

/** Resolve originating invoice number for statutory receipt HTML (never expose raw UUIDs). */
export async function resolveOriginatingInvoiceNumber(
  db: Db,
  tenantId: string,
  receipt: ReceiptObject,
): Promise<string | undefined> {
  if (!receipt.invoiceId) {
    if (receipt.docType === 'invoice_receipt' && receipt.receiptNumber) {
      return receipt.receiptNumber
    }
    return undefined
  }

  const invoice = await getInvoice(db, tenantId, receipt.invoiceId)
  return invoice?.invoiceNumber ?? undefined
}

/** Load tenant/customer identity + originating invoice number for receipt HTML rendering. */
export async function loadReceiptRenderContext(
  db: Db,
  env: Env,
  tenantId: string,
  receipt: ReceiptObject,
): Promise<ReceiptRenderContext> {
  const identity = await loadInvoiceRenderIdentity(db, tenantId, receipt.customerId)
  const invoiceNumber = await resolveOriginatingInvoiceNumber(db, tenantId, receipt)
  const r2PublicUrl =
    (env as Env & { INVOICE_SNAPSHOTS_PUBLIC_URL?: string }).INVOICE_SNAPSHOTS_PUBLIC_URL?.trim() ||
    undefined

  return {
    tenantName: identity.tenantName,
    tenantTaxId: identity.tenantTaxId,
    tenantAddress: identity.tenantAddress,
    customerName: identity.customerName,
    customerTaxId: identity.customerTaxId,
    customerAddress: identity.customerAddress,
    invoiceNumber,
    r2PublicUrl,
  }
}

/**
 * Render an ISSUED receipt and store its HTML in R2 (idempotent — safe to retry).
 * Returns the updated receipt when the snapshot key is persisted, null when R2 is not
 * configured (logged), or the loaded receipt when already snapshotted.
 */
export async function generateAndStoreReceiptSnapshot(
  deps: ReceiptSnapshotDeps,
  tenantId: string,
  receiptId: string,
): Promise<ReceiptObject | null> {
  const run = async (): Promise<ReceiptObject | null> => {
    const issued = await getReceiptWithLines(deps.db, tenantId, receiptId)
    if (!issued) {
      throw new Error('Receipt not found')
    }
    if (issued.status !== 'ISSUED') {
      throw new Error(`Cannot snapshot receipt in status ${issued.status}`)
    }
    if (!issued.receiptNumber) {
      throw new Error('Cannot snapshot receipt without receipt number')
    }
    if (issued.pdfR2Key) {
      return issued
    }

    const r2 = deps.env.INVOICE_SNAPSHOTS_BUCKET
    if (!r2) {
      console.warn('[receipt-snapshot] INVOICE_SNAPSHOTS_BUCKET not bound — skipping HTML snapshot')
      return null
    }

    const identity = await loadInvoiceRenderIdentity(deps.db, tenantId, issued.customerId)
    const invoiceNumber = await resolveOriginatingInvoiceNumber(deps.db, tenantId, issued)
    const r2PublicUrl =
      (deps.env as Env & { INVOICE_SNAPSHOTS_PUBLIC_URL?: string }).INVOICE_SNAPSHOTS_PUBLIC_URL?.trim() ||
      undefined

    const html = renderReceiptHtml(issued, {
      tenantName: identity.tenantName,
      tenantTaxId: identity.tenantTaxId,
      tenantAddress: identity.tenantAddress,
      customerName: identity.customerName,
      customerTaxId: identity.customerTaxId,
      customerAddress: identity.customerAddress,
      invoiceNumber,
      r2PublicUrl,
    })

    const lang = localeLangSubtag(identity.locale)
    const key = receiptSnapshotR2Key(tenantId, receiptId, issued.receiptNumber, lang)
    await r2.put(key, html, { httpMetadata: { contentType: 'text/html; charset=utf-8' } })
    return setReceiptPdfR2Key(deps.db, tenantId, receiptId, key)
  }

  const work = run()
  if (deps.executionCtx) {
    deps.executionCtx.waitUntil(
      work.catch((err) => {
        console.error('[receipt-snapshot] background snapshot failed:', err)
      }),
    )
  }
  return work
}

/** Re-export generic R2 fetch — snapshot keys are bucket-agnostic. */
export { fetchInvoiceHtmlSnapshot as fetchReceiptHtmlSnapshot }
