/**
 * Invoice adapter reconciliation cron — P056 invoices-adapters.
 *
 * POST /api/cron/invoice-adapter-reconcile
 *
 * Triggered daily by Cloudflare Cron Triggers (configured in wrangler.toml).
 * For each tenant that has at least one IL invoice adapter configured,
 * finds all pushable invoices and pushes them to configured providers.
 *
 * Security: cron-secret header (c.env.CRON_SECRET). Route NOT auth-middleware.
 */
import { Hono } from 'hono'
import { sql } from '@zync/db'
import {
  getAdapterConfig,
  getPendingInvoices,
  logSyncEvent,
  IL_INVOICE_PROVIDERS,
} from '@zync/db/queries'
import { timingSafeEqual } from '@zync/auth'
import {
  createMorningAdapter,
  createICountAdapter,
  createRivhitAdapter,
  createInvoice4uAdapter,
  createEasycountAdapter,
} from '../../integrations/invoice-adapters'
import type { AppEnv } from '../../types'
import type { ILInvoiceProvider, AdapterConfig } from '@zync/db/queries'

// ── Adapter factory ───────────────────────────────────────────────────────────

function getAdapter(provider: ILInvoiceProvider, config: AdapterConfig) {
  switch (provider) {
    case 'morning':    return createMorningAdapter(config)
    case 'icount':     return createICountAdapter(config)
    case 'rivhit':     return createRivhitAdapter(config)
    case 'invoice4u':  return createInvoice4uAdapter(config)
    case 'easycount':  return createEasycountAdapter(config)
  }
}

// ── Router ────────────────────────────────────────────────────────────────────

export const invoiceAdapterCron = new Hono<AppEnv>()

invoiceAdapterCron.post('/', async (c) => {
  // Validate cron secret
  const secret = c.req.header('x-cron-secret') ?? ''
  const expected = c.env.CRON_SECRET
  if (!expected || expected.length < 16) {
    return c.json({ error: 'Server misconfigured' }, 500)
  }
  if (!timingSafeEqual(secret, expected)) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  const db = c.get('db')
  if (!db) {
    // Cron context — create db
    const { createDb } = await import('@zync/db/queries')
    c.set('db', createDb(c.env))
  }
  const dbHandle = c.get('db')

  // Get all tenants that have adapter_credentials with invoice: prefix
  const tenantRows = await dbHandle.execute(sql`
    SELECT DISTINCT tenant_id::text AS tenant_id
    FROM adapter_credentials
    WHERE adapter_id LIKE 'invoice:%'
  `) as unknown as Array<{ tenant_id: string }>

  const results: Array<{
    tenantId: string
    provider: string
    pushed: number
    failed: number
    errors: string[]
  }> = []

  for (const { tenant_id: tenantId } of tenantRows) {
    for (const provider of IL_INVOICE_PROVIDERS) {
      const config = await getAdapterConfig(
        dbHandle,
        tenantId,
        provider,
        c.env.INTEGRATION_ENCRYPTION_KEY,
      )
      if (!config) continue

      const invoices = await getPendingInvoices(dbHandle, tenantId, provider, 100)
      if (invoices.length === 0) continue

      let pushed = 0
      let failed = 0
      const errors: string[] = []

      const adapter = getAdapter(provider, config)

      for (const invoice of invoices) {
        const start = Date.now()
        try {
          const externalId = await adapter.pushInvoice(invoice.id, tenantId, dbHandle)
          const durationMs = Date.now() - start

          await logSyncEvent(dbHandle, {
            tenantId,
            provider,
            entityType: 'invoice',
            entityId: invoice.id,
            externalId,
            direction: 'push',
            status: 'success',
            durationMs,
          })
          pushed++
        } catch (err) {
          const durationMs = Date.now() - start
          const message = err instanceof Error ? err.message : 'Unknown error'
          const httpStatus = (err as { httpStatus?: number }).httpStatus

          await logSyncEvent(dbHandle, {
            tenantId,
            provider,
            entityType: 'invoice',
            entityId: invoice.id,
            direction: 'push',
            status: 'failure',
            httpStatus,
            durationMs,
            errorPayload: { message },
          })

          failed++
          errors.push(`${invoice.id}: ${message}`)
        }
      }

      results.push({ tenantId, provider, pushed, failed, errors })
    }
  }

  return c.json({
    ok: true,
    summary: {
      tenantsProcessed: tenantRows.length,
      results,
    },
  })
})
