/**
 * Invoice generation queue consumer — invoices-core wave 3.
 *
 * Handles `retainer.invoice` (legacy enqueue from incrementRetainerHours) and
 * unified `invoice.generate` messages (task-status, fixed-deposit).
 */
import type { MessageBatch } from '@cloudflare/workers-types'
import type { Env } from '@zync/types'
import { createDb } from '@zync/db/queries'
import {
  processRetainerInvoiceJob,
  processInvoiceGenerateJob,
  processBulkInvoiceGenerationJob,
  type RetainerInvoiceJob,
  type InvoiceGenerateJob,
  type BulkInvoiceQueueJob,
} from '@zync/db/queries'

type ZyncJobMessage = RetainerInvoiceJob | InvoiceGenerateJob | BulkInvoiceQueueJob

function isRetainerInvoiceJob(body: unknown): body is RetainerInvoiceJob {
  const b = body as RetainerInvoiceJob | null
  return b?.type === 'retainer.invoice' && !!b.tenant_id && !!b.project_id && !!b.month
}

function isInvoiceGenerateJob(body: unknown): body is InvoiceGenerateJob {
  const b = body as InvoiceGenerateJob | null
  return b?.type === 'invoice.generate' && !!b.tenantId && !!b.projectId && !!b.reason
}

function isBulkInvoiceGenerationJob(body: unknown): body is BulkInvoiceQueueJob {
  const b = body as BulkInvoiceQueueJob | null
  return (
    b?.type === 'bulk_action' &&
    b?.action === 'invoice_generate' &&
    !!b.jobId &&
    !!b.tenantId &&
    !!b.actorId &&
    Array.isArray(b?.params?.customerIds)
  )
}

export async function handleInvoiceGenerateBatch(
  batch: MessageBatch<ZyncJobMessage>,
  env: Env,
): Promise<void> {
  const db = createDb(env)

  for (const msg of batch.messages) {
    const body = msg.body

    try {
      if (isRetainerInvoiceJob(body)) {
        const result = await processRetainerInvoiceJob(db, body)
        console.info('[invoice-generate] retainer.invoice', {
          tenantId: body.tenant_id,
          projectId: body.project_id,
          month: body.month,
          invoiceId: result.invoiceId,
          skipped: result.skipped,
        })
        msg.ack()
        continue
      }

      if (isInvoiceGenerateJob(body)) {
        const result = await processInvoiceGenerateJob(db, body)
        console.info('[invoice-generate] invoice.generate', {
          tenantId: body.tenantId,
          projectId: body.projectId,
          reason: body.reason,
          invoiceId: result.invoiceId,
          skipped: result.skipped,
        })
        msg.ack()
        continue
      }

      if (isBulkInvoiceGenerationJob(body)) {
        await processBulkInvoiceGenerationJob(db, body)
        msg.ack()
        continue
      }

      console.warn('[invoice-generate] Malformed job, discarding:', body)
      msg.ack()
    } catch (err) {
      console.error('[invoice-generate] Transient failure, will retry:', err)
      msg.retry()
    }
  }
}

/** Process a heterogeneous list of invoice jobs (used by zync-jobs batch router). */
export async function handleInvoiceGenerateMessages(
  messages: Array<{ body: unknown; ack: () => void; retry: () => void }>,
  env: Env,
): Promise<void> {
  const db = createDb(env)

  for (const msg of messages) {
    const body = msg.body

    try {
      if (isRetainerInvoiceJob(body)) {
        await processRetainerInvoiceJob(db, body)
        msg.ack()
        continue
      }

      if (isInvoiceGenerateJob(body)) {
        await processInvoiceGenerateJob(db, body)
        msg.ack()
        continue
      }

      if (isBulkInvoiceGenerationJob(body)) {
        await processBulkInvoiceGenerationJob(db, body)
        msg.ack()
        continue
      }

      console.warn('[invoice-generate] Malformed job, discarding:', body)
      msg.ack()
    } catch (err) {
      console.error('[invoice-generate] Transient failure, will retry:', err)
      msg.retry()
    }
  }
}
