'use client'

import * as React from 'react'
import clsx from 'clsx'
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/20/solid'

type PageItem = number | 'ellipsis'

export type PaginationProps = {
  page: number // 1-based
  pageSize: number
  totalItems: number
  onPageChange: (page: number) => void

  /** wie viele Seiten links/rechts neben aktueller Seite */
  siblingCount?: number
  /** wie viele Seiten am Anfang/Ende immer gezeigt werden */
  boundaryCount?: number

  /** Summary "Showing x to y of z" anzeigen */
  showSummary?: boolean
  /** Wrapper Klassen */
  className?: string

  /** Labels (optional) */
  ariaLabel?: string
  prevLabel?: string
  nextLabel?: string
}

function clamp(n: number, min: number, max: number) {
  return Math.max(min, Math.min(max, n))
}

function range(start: number, end: number): number[] {
  const out: number[] = []
  for (let i = start; i <= end; i++) out.push(i)
  return out
}

function getPageItems(
  totalPages: number,
  current: number,
  boundaryCount: number,
  siblingCount: number
): PageItem[] {
  if (totalPages <= 1) return [1]

  const first = 1
  const last = totalPages

  const startPages = range(first, Math.min(boundaryCount, last))
  const endPages = range(Math.max(last - boundaryCount + 1, boundaryCount + 1), last)

  const siblingsStart = Math.max(
    Math.min(
      current - siblingCount,
      last - boundaryCount - siblingCount * 2 - 1
    ),
    boundaryCount + 1
  )

  const siblingsEnd = Math.min(
    Math.max(
      current + siblingCount,
      boundaryCount + siblingCount * 2 + 2
    ),
    last - boundaryCount
  )

  const items: PageItem[] = []

  // start
  items.push(...startPages)

  // left gap
  if (siblingsStart > boundaryCount + 1) {
    items.push('ellipsis')
  } else if (boundaryCount + 1 < last - boundaryCount) {
    items.push(boundaryCount + 1)
  }

  // siblings
  items.push(...range(siblingsStart, siblingsEnd))

  // right gap
  if (siblingsEnd < last - boundaryCount) {
    items.push('ellipsis')
  } else if (last - boundaryCount > boundaryCount) {
    items.push(last - boundaryCount)
  }

  // end
  items.push(...endPages)

  // dedupe + keep order
  const seen = new Set<string>()
  return items.filter((x) => {
    const k = String(x)
    if (seen.has(k)) return false
    seen.add(k)
    return true
  })
}

function PageButton({
  active,
  disabled,
  rounded,
  onClick,
  children,
  title,
}: {
  active?: boolean
  disabled?: boolean
  rounded?: 'l' | 'r' | 'none'
  onClick?: () => void
  children: React.ReactNode
  title?: string
}) {
  const roundedCls =
    rounded === 'l' ? 'rounded-l-md' : rounded === 'r' ? 'rounded-r-md' : ''

  return (
    <button
      type="button"
      disabled={disabled}
      onClick={disabled ? undefined : onClick}
      title={title}
      className={clsx(
        'relative inline-flex items-center px-4 py-2 text-sm font-semibold focus:z-20 focus:outline-offset-0',
        roundedCls,
        disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer',
        active
          ? 'z-10 bg-indigo-600 text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 dark:bg-indigo-500 dark:focus-visible:outline-indigo-500'
          : 'text-gray-900 inset-ring inset-ring-gray-300 hover:bg-gray-50 dark:text-gray-200 dark:inset-ring-gray-700 dark:hover:bg-white/5'
      )}
      aria-current={active ? 'page' : undefined}
    >
      {children}
    </button>
  )
}

export default function Pagination({
  page,
  pageSize,
  totalItems,
  onPageChange,
  siblingCount = 1,
  boundaryCount = 1,
  showSummary = true,
  className,
  ariaLabel = 'Pagination',
  prevLabel = 'Previous',
  nextLabel = 'Next',
}: PaginationProps) {
  const totalPages = Math.max(1, Math.ceil((totalItems || 0) / Math.max(1, pageSize || 1)))
  const current = clamp(page || 1, 1, totalPages)

  if (totalPages <= 1) return null

  const from = totalItems === 0 ? 0 : (current - 1) * pageSize + 1
  const to = Math.min(current * pageSize, totalItems)

  const items = getPageItems(totalPages, current, boundaryCount, siblingCount)

  const go = (p: number) => onPageChange(clamp(p, 1, totalPages))

  return (
    <div
      className={clsx(
        'flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 dark:border-white/10 dark:bg-transparent',
        className
      )}
    >
      {/* Mobile: nur Previous/Next */}
      <div className="flex flex-1 justify-between sm:hidden">
        <button
          type="button"
          onClick={() => go(current - 1)}
          disabled={current <= 1}
          className="relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed dark:border-white/10 dark:bg-white/5 dark:text-gray-200 dark:hover:bg-white/10"
        >
          {prevLabel}
        </button>
        <button
          type="button"
          onClick={() => go(current + 1)}
          disabled={current >= totalPages}
          className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed dark:border-white/10 dark:bg-white/5 dark:text-gray-200 dark:hover:bg-white/10"
        >
          {nextLabel}
        </button>
      </div>

      {/* Desktop: Summary + Zahlen */}
      <div className="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
        <div>
          {showSummary ? (
            <p className="text-sm text-gray-700 dark:text-gray-300">
              Showing <span className="font-medium">{from}</span> to{' '}
              <span className="font-medium">{to}</span> of{' '}
              <span className="font-medium">{totalItems}</span> results
            </p>
          ) : null}
        </div>

        <div>
          <nav
            aria-label={ariaLabel}
            className="isolate inline-flex -space-x-px rounded-md shadow-xs dark:shadow-none"
          >
            <button
              type="button"
              onClick={() => go(current - 1)}
              disabled={current <= 1}
              className="relative inline-flex items-center rounded-l-md px-2 py-2 text-gray-400 inset-ring inset-ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0 disabled:opacity-50 disabled:cursor-not-allowed dark:inset-ring-gray-700 dark:hover:bg-white/5"
            >
              <span className="sr-only">{prevLabel}</span>
              <ChevronLeftIcon aria-hidden="true" className="size-5" />
            </button>

            {items.map((it, idx) => {
              if (it === 'ellipsis') {
                return (
                  <span
                    key={`e-${idx}`}
                    className="relative inline-flex items-center px-4 py-2 text-sm font-semibold text-gray-700 inset-ring inset-ring-gray-300 dark:text-gray-400 dark:inset-ring-gray-700"
                  >
                    …
                  </span>
                )
              }

              return (
                <PageButton
                  key={it}
                  active={it === current}
                  onClick={() => go(it)}
                  rounded="none"
                >
                  {it}
                </PageButton>
              )
            })}

            <button
              type="button"
              onClick={() => go(current + 1)}
              disabled={current >= totalPages}
              className="relative inline-flex items-center rounded-r-md px-2 py-2 text-gray-400 inset-ring inset-ring-gray-300 hover:bg-gray-50 focus:z-20 focus:outline-offset-0 disabled:opacity-50 disabled:cursor-not-allowed dark:inset-ring-gray-700 dark:hover:bg-white/5"
            >
              <span className="sr-only">{nextLabel}</span>
              <ChevronRightIcon aria-hidden="true" className="size-5" />
            </button>
          </nav>
        </div>
      </div>
    </div>
  )
}
