<script setup lang="ts">
import { computed } from 'vue'

const props = withDefaults(
  defineProps<{
    current: number
    pageSize: number
    total: number
    maxVisiblePages?: number
  }>(),
  {
    maxVisiblePages: 5,
  },
)

const emit = defineEmits<{
  (event: 'change', page: number): void
}>()

type PageToken = number | 'ellipsis'

const totalPages = computed(() => Math.max(1, Math.ceil(props.total / props.pageSize)))

const tokens = computed<PageToken[]>(() => {
  if (totalPages.value <= props.maxVisiblePages) {
    return Array.from({ length: totalPages.value }, (_value, index) => index + 1)
  }

  const pages: PageToken[] = [1]
  let start = Math.max(2, props.current - 1)
  let end = Math.min(totalPages.value - 1, props.current + 1)

  while (end - start < 2 && start > 2) {
    start -= 1
  }
  while (end - start < 2 && end < totalPages.value - 1) {
    end += 1
  }

  if (start > 2) {
    pages.push('ellipsis')
  }

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

  if (end < totalPages.value - 1) {
    pages.push('ellipsis')
  }

  pages.push(totalPages.value)
  return pages
})

function goTo(page: number) {
  if (page === props.current || page < 1 || page > totalPages.value) {
    return
  }
  emit('change', page)
}
</script>

<template>
  <nav v-if="totalPages > 1" class="pagination" aria-label="Pagination">
    <button class="pagination__nav" :disabled="props.current <= 1" @click="goTo(props.current - 1)">
      上一页
    </button>

    <div class="pagination__pages">
      <template
        v-for="token in tokens"
        :key="`${token}-${typeof token === 'number' ? token : Math.random()}`"
      >
        <span v-if="token === 'ellipsis'" class="pagination__ellipsis">…</span>
        <button
          v-else
          class="pagination__page"
          :class="{ active: token === props.current }"
          @click="goTo(token)"
        >
          {{ token }}
        </button>
      </template>
    </div>

    <button
      class="pagination__nav"
      :disabled="props.current >= totalPages"
      @click="goTo(props.current + 1)"
    >
      下一页
    </button>
  </nav>
</template>

<style scoped>
.pagination {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}

.pagination__pages {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.pagination__nav,
.pagination__page {
  appearance: none;
  min-width: 34px;
  height: 34px;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid #dbe5f0;
  background: #ffffff;
  color: #334155;
  cursor: pointer;
  font-size: 12px;
  font-weight: 600;
  transition:
    background-color 0.2s ease,
    border-color 0.2s ease,
    color 0.2s ease,
    opacity 0.2s ease;
}

.pagination__nav:hover:not(:disabled),
.pagination__page:hover:not(:disabled) {
  background: #f8fafc;
  border-color: #bfdbfe;
}

.pagination__nav:disabled,
.pagination__page:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

.pagination__page.active {
  background: #1677ff;
  border-color: #1677ff;
  color: #ffffff;
}

.pagination__ellipsis {
  width: 18px;
  text-align: center;
  color: #94a3b8;
  font-size: 14px;
}
</style>
