/**
 * /v1/events routes — tenant-public-api (wave-11 leaf-D).
 * Read-only webhook delivery audit log (webhook_deliveries + endpoint URL join).
 *
 * GET /v1/events — list events (paginated)
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { and, desc, eq, lt, or } from 'drizzle-orm'
import { webhookDeliveries, webhookEndpoints } from '@zync/db/schema'
import {
  hasScope,
  serializeEvent,
  errForbiddenScope,
  errValidation,
  decodeCursor,
  encodeCursor,
} from '@zync/public-api'
import type { ApiKeyContext } from '../middleware/auth'
import type { Env } from '../env'
import { createDb } from '../db'

type AppEnv = { Bindings: Env }

export const eventsRouter = new Hono<AppEnv>()

const listQuerySchema = z.object({
  limit: z.coerce.number().int().min(1).max(100).default(20),
  cursor: z.string().optional(),
  status: z.string().optional(),
})

eventsRouter.get('/', async (c) => {
  const apiKey = c.get('apiKey' as never) as ApiKeyContext
  if (!hasScope(apiKey.scopes, 'events:read')) {
    return errForbiddenScope('events:read')
  }

  const parsed = listQuerySchema.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!parsed.success) {
    return errValidation('Invalid query parameters')
  }

  const cursorPayload = parsed.data.cursor ? decodeCursor(parsed.data.cursor) : null
  if (parsed.data.cursor && !cursorPayload) {
    return errValidation('Invalid cursor', 'cursor')
  }

  const db = createDb(c.env)

  const conditions = [eq(webhookDeliveries.tenantId, apiKey.tenantId)]
  if (parsed.data.status) {
    conditions.push(eq(webhookDeliveries.status, parsed.data.status))
  }
  if (cursorPayload) {
    const cursorAt = new Date(cursorPayload.created_at)
    conditions.push(
      or(
        lt(webhookDeliveries.createdAt, cursorAt),
        and(
          eq(webhookDeliveries.createdAt, cursorAt),
          lt(webhookDeliveries.id, cursorPayload.id),
        ),
      )!,
    )
  }

  const rows = await db
    .select({
      id: webhookDeliveries.id,
      tenantId: webhookDeliveries.tenantId,
      endpointId: webhookDeliveries.endpointId,
      eventType: webhookDeliveries.eventType,
      status: webhookDeliveries.status,
      responseStatus: webhookDeliveries.responseStatus,
      responseBody: webhookDeliveries.responseBody,
      latencyMs: webhookDeliveries.latencyMs,
      attempt: webhookDeliveries.attempt,
      createdAt: webhookDeliveries.createdAt,
      endpointUrl: webhookEndpoints.url,
    })
    .from(webhookDeliveries)
    .leftJoin(webhookEndpoints, eq(webhookDeliveries.endpointId, webhookEndpoints.id))
    .where(and(...conditions))
    .orderBy(desc(webhookDeliveries.createdAt), desc(webhookDeliveries.id))
    .limit(parsed.data.limit + 1)

  const hasMore = rows.length > parsed.data.limit
  const data = rows.slice(0, parsed.data.limit)
  const last = data[data.length - 1]
  const nextCursor =
    hasMore && last ? encodeCursor(last.id, last.createdAt.toISOString()) : null

  return c.json({
    data: data.map((row) =>
      serializeEvent({
        id: row.id,
        endpointId: row.endpointId,
        eventType: row.eventType,
        status: row.status,
        responseStatus: row.responseStatus ?? null,
        latencyMs: row.latencyMs ?? null,
        attempt: row.attempt,
        createdAt: row.createdAt,
        endpointUrl: row.endpointUrl ?? null,
      }),
    ),
    meta: {
      has_more: hasMore,
      next_cursor: nextCursor,
      limit: parsed.data.limit,
    },
  })
})
