import { NextRequest, NextResponse } from 'next/server'
import { createHmac, timingSafeEqual } from 'node:crypto'
import { eventsFromPayload, processIncomingEvents } from '@/lib/email/events'

export const runtime = 'nodejs'

/**
 * ZeptoMail → HeavyHaul Agent (2026-09-22). One endpoint per Mail Agent:
 *
 *   /api/webhooks/zeptomail/transactional   HHA Transactional (info@)
 *   /api/webhooks/zeptomail/updates         HHA Updates (updates@)
 *
 * Both feed processIncomingEvents. Two ways to authenticate, either accepted:
 *   1. ZeptoMail's signed webhooks: HMAC-SHA256 of the raw body with the
 *      agent's webhook key. Header name is configurable
 *      (ZEPTOMAIL_WEBHOOK_SIGNATURE_HEADER, default "zoho-webhook-signature";
 *      confirm it in the ZeptoMail console) — base64 or hex accepted.
 *   2. A shared secret in the "x-hha-webhook-secret" header or ?key=.
 * Secrets: ZEPTOMAIL_WEBHOOK_SECRET_TRANSACTIONAL / _UPDATES (fallback
 * ZEPTOMAIL_WEBHOOK_SECRET). Replays are harmless: every event is stored
 * under a dedupe key and processed once.
 */
const AGENTS = new Set(['transactional', 'updates'])

function secretFor(agent: string): string | null {
  return (agent === 'updates' ? process.env.ZEPTOMAIL_WEBHOOK_SECRET_UPDATES : process.env.ZEPTOMAIL_WEBHOOK_SECRET_TRANSACTIONAL)?.trim() || process.env.ZEPTOMAIL_WEBHOOK_SECRET?.trim() || null
}

function safeEqual(a: string, b: string): boolean {
  const A = Buffer.from(a), B = Buffer.from(b)
  return A.length === B.length && timingSafeEqual(A, B)
}

function authorised(req: NextRequest, agent: string, rawBody: string): boolean {
  const secret = secretFor(agent)
  if (!secret) return false
  const sigHeader = (process.env.ZEPTOMAIL_WEBHOOK_SIGNATURE_HEADER || 'zoho-webhook-signature').toLowerCase()
  const sig = req.headers.get(sigHeader)
  if (sig) {
    const mac = createHmac('sha256', secret).update(rawBody)
    const digest = mac.digest()
    const candidates = [digest.toString('base64'), digest.toString('hex'), digest.toString('base64url')]
    if (candidates.some((c) => safeEqual(c, sig.trim()))) return true
  }
  const shared = req.headers.get('x-hha-webhook-secret') ?? req.nextUrl.searchParams.get('key')
  return !!shared && safeEqual(shared, secret)
}

export async function GET(req: NextRequest, ctx: { params: Promise<{ agent: string }> }) {
  const { agent } = await ctx.params
  if (!AGENTS.has(agent)) return NextResponse.json({ error: 'Unknown agent' }, { status: 404 })
  if (!authorised(req, agent, '')) return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
  return NextResponse.json({ ok: true, service: `HeavyHaul Agent email webhook (${agent})` })
}

export async function POST(req: NextRequest, ctx: { params: Promise<{ agent: string }> }) {
  const { agent } = await ctx.params
  if (!AGENTS.has(agent)) return NextResponse.json({ error: 'Unknown agent' }, { status: 404 })
  const raw = await req.text()
  if (!authorised(req, agent, raw)) return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
  let payload: unknown = null
  try { payload = raw ? JSON.parse(raw) : null } catch { payload = null }
  const events = eventsFromPayload(agent as 'transactional' | 'updates', payload)
  // ZeptoMail's rules: answer 200 once authenticated, even for the console's "Verify" call.
  if (events.length === 0) return NextResponse.json({ ok: true, stored: 0, duplicates: 0, suppressed: 0, unmatched: 0, note: 'no recipient events in payload' })
  const result = await processIncomingEvents(events)
  return NextResponse.json({ ok: true, ...result })
}
