/**
 * Inbound Webhook configuration routes — marketing-leads-pipeline.
 * Mounted at /api/marketing/webhooks (behind authMiddleware in router.ts).
 * Business+ tier gate applied per-route.
 *
 * GET    /          list webhook configs
 * POST   /          create webhook config (Business+)
 * GET    /:id       webhook config detail
 * PATCH  /:id       update webhook config
 * DELETE /:id       delete webhook config
 *
 * The actual inbound webhook receiver (POST /api/webhooks/leads/:webhookId)
 * lives in public-form.ts and is mounted at top-level (no auth) by the integrator.
 */
import { Hono } from 'hono'
import type { AppEnv } from '../../types'
import { requirePermission } from '../../middleware/guards'
import {
  listLeadWebhooks,
  getLeadWebhook,
  createLeadWebhook,
  updateLeadWebhook,
  deleteLeadWebhook,
  createLeadWebhookSchema,
  updateLeadWebhookSchema,
} from '@zync/db/queries'

// ── Encryption helpers ────────────────────────────────────────────────────────

async function encryptSecret(plaintext: string, keyHex: string): Promise<string> {
  const keyBytes = hexToBytes(keyHex)
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    keyBytes,
    { name: 'AES-GCM' },
    false,
    ['encrypt'],
  )
  const iv = crypto.getRandomValues(new Uint8Array(12))
  const enc = new TextEncoder()
  const ciphertext = await crypto.subtle.encrypt(
    { name: 'AES-GCM', iv },
    cryptoKey,
    enc.encode(plaintext),
  )
  return `${bytesToHex(iv)}:${bytesToHex(new Uint8Array(ciphertext))}`
}

function hexToBytes(hex: string): Uint8Array {
  const bytes = new Uint8Array(hex.length / 2)
  for (let i = 0; i < hex.length; i += 2) {
    bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16)
  }
  return bytes
}

function bytesToHex(bytes: Uint8Array): string {
  return Array.from(bytes)
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('')
}

export const webhooksRoute = new Hono<AppEnv>()

// ── List webhooks ─────────────────────────────────────────────────────────────

webhooksRoute.get('/', requirePermission('marketing:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')

  const webhooks = await listLeadWebhooks(db, session.tid)
  return c.json({ webhooks })
})

// ── Create webhook ────────────────────────────────────────────────────────────

webhooksRoute.post(
  '/',
  requirePermission('marketing:write'),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
    const db = c.get('db')

    const body = await c.req.json().catch(() => null)
    const parsed = createLeadWebhookSchema.safeParse(body)
    if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)
    const input = parsed.data

    // Business+ tier gate (fail-closed: missing tier → deny)
    if (!session.tier || !['business', 'enterprise'].includes(session.tier)) {
      return c.json({ error: 'Inbound webhooks require Business plan or higher', upgrade: true }, 403)
    }

    const encKey = (c.env as { INTEGRATION_ENCRYPTION_KEY?: string }).INTEGRATION_ENCRYPTION_KEY
    if (!encKey) {
      return c.json({ error: 'Webhook encryption key not configured' }, 500)
    }

    const encryptedSecret = await encryptSecret(input.secret, encKey)
    const webhook = await createLeadWebhook(db, session.tid, input, encryptedSecret)
    return c.json({ webhook, secret: input.secret }, 201)
  },
)

// ── Webhook detail ────────────────────────────────────────────────────────────

webhooksRoute.get('/:id', requirePermission('marketing:read'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  const webhook = await getLeadWebhook(db, session.tid, id)
  if (!webhook) return c.json({ error: 'Not found' }, 404)

  return c.json({
    webhook: {
      id: webhook.id,
      tenantId: webhook.tenantId,
      name: webhook.name,
      source: webhook.source,
      fieldMapping: webhook.fieldMapping,
      isActive: webhook.isActive,
      lastReceivedAt: webhook.lastReceivedAt?.toISOString() ?? null,
      createdAt: webhook.createdAt.toISOString(),
    },
  })
})

// ── Update webhook ────────────────────────────────────────────────────────────

webhooksRoute.patch(
  '/:id',
  requirePermission('marketing:write'),
  async (c) => {
    const session = c.get('session')
    if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
    const db = c.get('db')
    const { id } = c.req.param()

    const body = await c.req.json().catch(() => null)
    const parsed = updateLeadWebhookSchema.safeParse(body)
    if (!parsed.success) return c.json({ error: 'Validation failed', issues: parsed.error.issues }, 400)
    const input = parsed.data

    const existing = await getLeadWebhook(db, session.tid, id)
    if (!existing) return c.json({ error: 'Not found' }, 404)

    let encryptedSecret: string | undefined
    if (input.secret) {
      const encKey = (c.env as { INTEGRATION_ENCRYPTION_KEY?: string }).INTEGRATION_ENCRYPTION_KEY
      if (!encKey) return c.json({ error: 'Webhook encryption key not configured' }, 500)
      encryptedSecret = await encryptSecret(input.secret, encKey)
    }

    const webhook = await updateLeadWebhook(db, session.tid, id, input, encryptedSecret)
    return c.json({ webhook })
  },
)

// ── Delete webhook ────────────────────────────────────────────────────────────

webhooksRoute.delete('/:id', requirePermission('marketing:write'), async (c) => {
  const session = c.get('session')
  if (!session || session.type !== 'user' || !session.tid) return c.json({ error: 'Unauthorized' }, 401)
  const db = c.get('db')
  const { id } = c.req.param()

  const existing = await getLeadWebhook(db, session.tid, id)
  if (!existing) return c.json({ error: 'Not found' }, 404)

  await deleteLeadWebhook(db, session.tid, id)
  return c.json({ ok: true })
})
