/**
 * Telegram inbound webhook receiver — system-communications-notifications (Task 14).
 *
 * POST /api/webhooks/telegram/:tenantId
 *
 * 1. Look up tenant bot token via loadAdapterCredential.
 * 2. Verify X-Telegram-Bot-Api-Secret-Token header (timing-safe).
 * 3. Parse Telegram update → InboundMessage.
 * 4. Enqueue { tenantId, source: 'telegram', message } to comms.inbound queue.
 * 5. Return 200 fast (processing is async).
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { timingSafeEqual, decryptCredential } from '@zync/auth'
import { createDb, loadAdapterCredentialRow } from '@zync/db/queries'
import { createTelegramAdapter } from '@zync/notifications'
import type { AppEnv } from '../../types'
import { telegramUpdateSchema } from '../../schemas/webhooks'

const telegramWebhookRouter = new Hono<AppEnv>()

const tenantParamSchema = z.object({
  tenantId: z.string().uuid(),
})

telegramWebhookRouter.post('/:tenantId', async (c) => {
  const paramParsed = tenantParamSchema.safeParse({ tenantId: c.req.param('tenantId') })
  if (!paramParsed.success) {
    return c.json({ error: 'Invalid tenant ID' }, 400)
  }
  const { tenantId } = paramParsed.data

  const db = createDb(c.env)

  // Load the tenant's encrypted bot token
  const credRow = await loadAdapterCredentialRow(db, tenantId, 'telegram')
  if (!credRow) {
    // No bot configured for this tenant → silently 200 (don't reveal config)
    return c.json({ ok: true })
  }

  // Decrypt the bot token
  const decryptedToken = await decryptCredential(
    { ciphertext: credRow.ciphertext, iv: credRow.iv, authTag: credRow.authTag },
    c.env.INTEGRATION_ENCRYPTION_KEY,
  )

  // Verify X-Telegram-Bot-Api-Secret-Token — MANDATORY (no unsigned bypass).
  // Telegram echoes the secret_token set via setWebhook on every delivery, so a
  // missing header means the request is not from Telegram → reject.
  // NOTE: the expected secret is derived from the bot token; the tenantId half is
  // public (URL path), so the secret strength rests on the first 8 token chars.
  // Adapter-setup wave should store a separately-generated random webhook_secret
  // (passed to setWebhook's secret_token) to decouple rotation. Mandatory check
  // below closes the auth-bypass regardless.
  const secretHeader = c.req.header('X-Telegram-Bot-Api-Secret-Token')
  if (!secretHeader) {
    return c.json({ error: 'Unauthorized' }, 401)
  }
  const expectedSecret = `${decryptedToken.slice(0, 8)}_${tenantId.replace(/-/g, '').slice(0, 16)}`
  // Timing-safe comparison (never ===)
  if (!timingSafeEqual(secretHeader, expectedSecret)) {
    return c.json({ error: 'Unauthorized' }, 401)
  }

  // Parse + validate payload
  const bodyParsed = telegramUpdateSchema.safeParse(await c.req.json())
  if (!bodyParsed.success) {
    return c.json({ error: 'Invalid request', issues: bodyParsed.error.issues }, 400)
  }

  const adapter = createTelegramAdapter(decryptedToken)

  const inboundMessage = adapter.receive?.(bodyParsed.data)
  if (!inboundMessage) {
    // Not a message update (e.g. edited_message) — ack and return
    return c.json({ ok: true })
  }

  // Enqueue for async processing — return 200 immediately
  await c.env.QUEUE.send({
    type: 'comms.inbound',
    source: 'telegram',
    tenantId,
    message: inboundMessage,
    receivedAt: new Date().toISOString(),
  })

  return c.json({ ok: true })
})

export { telegramWebhookRouter }
