<script lang="ts">
  interface Props {
    currentPage: number;
    totalPages: number;
    totalItems: number;
    pageSize: number;
    maxVisiblePages?: number;
    onPageChange: (page: number) => void;
  }

  const MIN_VISIBLE_PAGES = 3;
  const ellipsis = 'ellipsis' as const;
  type PageItem = number | typeof ellipsis;

  let {
    currentPage,
    totalPages,
    totalItems,
    pageSize,
    maxVisiblePages = 5,
    onPageChange
  }: Props = $props();

  function calculatePageItems(): PageItem[] {
    if (totalPages <= 0) {
      return [];
    }

    const effectiveMaxPages = Math.max(MIN_VISIBLE_PAGES, maxVisiblePages);
    const visibleCount = Math.min(totalPages, effectiveMaxPages);

    if (totalPages <= visibleCount) {
      return Array.from({ length: totalPages }, (_, index) => index + 1);
    }

    const items: PageItem[] = [1];

    const innerSlots = effectiveMaxPages - 2;

    let start = currentPage - Math.floor(innerSlots / 2);
    let end = currentPage + Math.floor(innerSlots / 2);

    if (start < 2) {
      start = 2;
      end = start + innerSlots - 1;
    }

    if (end > totalPages - 1) {
      end = totalPages - 1;
      start = Math.max(2, end - innerSlots + 1);
    }

    if (start > 2) {
      items.push(ellipsis);
    }

    for (let page = start; page <= end; page += 1) {
      items.push(page);
    }

    if (end < totalPages - 1) {
      items.push(ellipsis);
    }

    items.push(totalPages);

    return items;
  }

  function getStartItem() {
    if (totalItems === 0) return 0;
    return Math.min(totalItems, (currentPage - 1) * pageSize + 1);
  }

  function getEndItem() {
    if (totalItems === 0) return 0;
    return Math.min(totalItems, currentPage * pageSize);
  }

  function goToPage(page: PageItem) {
    if (page === ellipsis) return;
    const pageNumber = page;
    if (pageNumber < 1 || pageNumber > totalPages || pageNumber === currentPage) return;
    onPageChange(pageNumber);
  }

  function previousPage() {
    if (currentPage > 1) {
      onPageChange(currentPage - 1);
    }
  }

  function nextPage() {
    if (currentPage < totalPages) {
      onPageChange(currentPage + 1);
    }
  }
</script>

{#if totalPages > 0}
  <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
    <p class="text-sm text-gray-600">
      Showing {getStartItem()}-{getEndItem()} of {totalItems}
    </p>

    <div class="join">
      <button
        type="button"
        class={`btn btn-sm join-item ${currentPage <= 1 ? 'btn-disabled' : ''}`}
        on:click={previousPage}
        aria-label="Previous page"
        disabled={currentPage <= 1}
      >
        «
      </button>

      {#each calculatePageItems() as item, index (item === ellipsis ? `ellipsis-${index}` : item)}
        {#if item === ellipsis}
          <span class="btn btn-sm join-item cursor-default">&hellip;</span>
        {:else}
          <button
            type="button"
            class={`btn btn-sm join-item ${item === currentPage ? 'btn-active' : ''}`}
            on:click={() => goToPage(item)}
          >
            {item}
          </button>
        {/if}
      {/each}

      <button
        type="button"
        class={`btn btn-sm join-item ${currentPage >= totalPages ? 'btn-disabled' : ''}`}
        on:click={nextPage}
        aria-label="Next page"
        disabled={currentPage >= totalPages}
      >
        »
      </button>
    </div>
  </div>
{:else}
  <p class="text-sm text-gray-600">Showing 0-0 of 0</p>
{/if}
