/**
 * Cursor pagination helpers — tenant-public-api (wave-11 leaf-D).
 * Cursor encodes `{ id: string, created_at: string }` as base64url.
 */
import { z } from 'zod'

export interface CursorPayload {
  id: string
  created_at: string
}

export interface PaginatedResult<T> {
  data: T[]
  meta: {
    total: number
    next_cursor: string | null
    has_more: boolean
    limit: number
  }
}

export function encodeCursor(id: string, createdAt: string | Date): string {
  const payload: CursorPayload = { id, created_at: String(createdAt) }
  return btoa(JSON.stringify(payload)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
}

export function decodeCursor(cursor: string): CursorPayload | null {
  try {
    // base64url → base64
    const b64 = cursor.replace(/-/g, '+').replace(/_/g, '/')
    const raw = atob(b64)
    const parsed = JSON.parse(raw) as { id?: unknown; created_at?: unknown }
    if (typeof parsed.id !== 'string' || typeof parsed.created_at !== 'string') return null
    const d = new Date(parsed.created_at)
    if (isNaN(d.getTime())) return null
    return { id: parsed.id, created_at: parsed.created_at }
  } catch {
    return null
  }
}

export function buildPaginatedResult<T extends { id: string; created_at: string }>(
  rows: T[],
  limit: number,
  total: number,
): PaginatedResult<T> {
  const hasMore = rows.length === limit
  const lastRow = rows[rows.length - 1]
  const nextCursor = hasMore && lastRow ? encodeCursor(lastRow.id, lastRow.created_at) : null

  return {
    data: rows,
    meta: {
      total,
      next_cursor: nextCursor,
      has_more: hasMore,
      limit,
    },
  }
}

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

export type PaginationInput = z.infer<typeof paginationSchema>
