import { createDb, getAdapterConfig, getInvoice, getInvoiceAdapterSettings, logSyncEvent } from '@zync/db/queries'
import type { Env } from '../env'
import { getAdapter, pushInvoiceToAdapter } from '../routes/invoice-adapters/router'

type InvoicePushJob = {
  type: 'invoice.push'
  tenantId: string
  invoiceId: string
}

type InvoicePaymentSyncJob = {
  type: 'invoice.payment_sync'
  tenantId: string
  invoiceId: string
}

type InvoiceAdapterJob = InvoicePushJob | InvoicePaymentSyncJob

export async function handleInvoiceAdapterMessages(
  messages: Message<unknown>[],
  env: Env,
): Promise<void> {
  const db = createDb(env)

  for (const msg of messages) {
    const job = msg.body as Partial<InvoiceAdapterJob>
    const tenantId = job.tenantId
    const invoiceId = job.invoiceId

    if (!tenantId || !invoiceId) {
      console.warn('[invoice-adapter-sync] missing tenantId or invoiceId', job)
      msg.ack()
      continue
    }

    try {
      const settings = await getInvoiceAdapterSettings(db, tenantId)
      if (!settings.adapter) {
        msg.ack()
        continue
      }

      const config = await getAdapterConfig(
        db,
        tenantId,
        settings.adapter,
        env.INTEGRATION_ENCRYPTION_KEY,
      )
      if (!config) {
        msg.ack()
        continue
      }

      if (job.type === 'invoice.push') {
        await pushInvoiceToAdapter({
          db,
          tenantId,
          provider: settings.adapter,
          invoiceId,
          config,
        })
        msg.ack()
        continue
      }

      if (job.type === 'invoice.payment_sync') {
        const invoice = await getInvoice(db, tenantId, invoiceId)
        if (!invoice?.externalId) {
          msg.ack()
          continue
        }

        const adapter = getAdapter(settings.adapter, config)
        if (!adapter.recordPayment) {
          await logSyncEvent(db, {
            tenantId,
            provider: settings.adapter,
            entityType: 'invoice',
            entityId: invoiceId,
            externalId: invoice.externalId,
            direction: 'push',
            status: 'skipped',
            errorPayload: { message: 'recordPayment unsupported by adapter' },
          })
          msg.ack()
          continue
        }

        await adapter.recordPayment(
          invoice.externalId,
          {
            amount: parseFloat(invoice.amountPaid),
            paidAt: invoice.paidAt ? new Date(invoice.paidAt) : new Date(),
            currency: invoice.currency ?? 'ILS',
            reference: invoice.invoiceNumber ?? invoice.id,
          },
          config,
        )
        await logSyncEvent(db, {
          tenantId,
          provider: settings.adapter,
          entityType: 'payment',
          entityId: invoiceId,
          externalId: invoice.externalId,
          direction: 'push',
          status: 'success',
        })
        msg.ack()
        continue
      }

      msg.ack()
    } catch (err) {
      console.error('[invoice-adapter-sync] job failed', { job, err })
      msg.retry()
    }
  }
}
