import { z } from 'zod'

export const LIMIT_ALL = -1

export type Pagination = {
  /**
   * The cursor is the page number that the user is currently on.
   *
   * NOTE: We do not use the term "page" because React Query/tRPC standardizes on "cursor" - see https://trpc.io/docs/client/react/useInfiniteQuery
   */
  cursor: number
  /**
   * The number of items per page.
   */
  limit: number
}
export const DEFAULT_PAGINATION: Pagination = { cursor: 1, limit: 100 }

export const paginationDecoder = z.object({
  cursor: z.number().int().nonnegative().optional().default(1),
  limit: z.number().int().positive().optional().default(DEFAULT_PAGINATION.limit),
})

export const paginationDecoderFromQuery = z.object({
  cursor: z.coerce.number().int().nonnegative().optional().default(1),
  limit: z.coerce.number().int().positive().optional().default(DEFAULT_PAGINATION.limit),
})

export type PaginatedResult<T> = {
  data: T[]
  total: number
  currentPage: number
  perPage: number
  cursor: number | null
}

export const paginatedResultDecoder = <T extends z.ZodTypeAny>(itemSchema: T) =>
  z.object({
    data: z.array(itemSchema),
    total: z.number(),
    currentPage: z.number(),
    perPage: z.number(),
    cursor: z.number().nullable(),
  })

export function paginate<T>(data: T[], pagination: Pagination): PaginatedResult<T> {
  if (data.length === 0) {
    return {
      data: [],
      total: 0,
      perPage: pagination.limit,
      currentPage: pagination.cursor,
      cursor: null,
    }
  }

  const paginatedData =
    pagination.limit === LIMIT_ALL
      ? data
      : data.slice((pagination.cursor - 1) * pagination.limit, pagination.cursor * pagination.limit)
  return {
    data: paginatedData,
    total: data.length,
    perPage: pagination.limit,
    currentPage: pagination.cursor,
    cursor: pagination.cursor * pagination.limit < data.length ? pagination.cursor + 1 : null,
  }
}
