<template>
  <div class="flex items-center justify-between py-4">
    <div class="text-sm text-gray-600">共 {{ total }} 项数据</div>
    <div class="flex items-center gap-2">
      <SelectRoot :modelValue="String(pageSize)" @update:modelValue="onPageSizeChange">
        <SelectTrigger class="inline-flex items-center justify-between rounded-md border border-gray-200 bg-white px-3 py-1 text-sm text-gray-700 shadow-sm hover:bg-gray-50">
          <span>{{ pageSize }} 条/页</span>
          <SelectIcon>
            <RiArrowDownSLine />
          </SelectIcon>
        </SelectTrigger>
        <SelectPortal>
          <SelectContent class="z-50 min-w-[120px] rounded-md border border-gray-200 bg-white shadow-lg">
            <SelectViewport class="p-1">
              <SelectItem v-for="s in pageSizes" :key="s" :value="String(s)" class="flex cursor-pointer select-none items-center rounded px-2 py-1 text-sm text-gray-700 hover:bg-gray-50">
                <SelectItemText>{{ s }} 条/页</SelectItemText>
              </SelectItem>
            </SelectViewport>
          </SelectContent>
        </SelectPortal>
      </SelectRoot>

      <button
        class="inline-flex h-8 w-8 items-center justify-center rounded border border-gray-200 bg-white text-gray-700 shadow-sm hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50"
        :disabled="page === 1"
        @click="go(page - 1)"
        aria-label="上一页"
      >
        <RiArrowLeftLine />
      </button>

      <div class="flex items-center gap-1">
        <template v-for="p in pages" :key="String(p) + '-' + page">
          <button
            v-if="typeof p === 'number'"
            class="inline-flex h-8 min-w-[32px] items-center justify-center rounded border border-gray-200 bg-white px-2 text-sm shadow-sm hover:bg-gray-50"
            :class="p === page ? 'border-blue-500 text-blue-600' : 'text-gray-700'"
            @click="go(p)"
          >
            {{ p }}
          </button>
          <span v-else class="inline-flex h-8 min-w-[32px] items-center justify-center rounded border border-transparent px-2 text-sm text-gray-400">…</span>
        </template>
      </div>

      <button
        class="inline-flex h-8 w-8 items-center justify-center rounded border border-gray-200 bg-white text-gray-700 shadow-sm hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-50"
        :disabled="page === totalPages"
        @click="go(page + 1)"
        aria-label="下一页"
      >
        <RiArrowRightLine />
      </button>

      <div class="ml-2 flex items-center gap-2 text-sm text-gray-700">
        <span>跳至</span>
        <input
          class="w-16 rounded border border-gray-200 bg-white px-2 py-1 text-center outline-none focus:border-blue-500"
          type="text"
          :min="1"
          :max="totalPages"
          v-model.number="jumpValue"
          @keydown.enter="onJump"
          @blur="onJump"
        />
        <span>/ {{ totalPages }} 页</span>
      </div>
    </div>
  </div>
  
</template>

<script setup lang="ts" name="Pagination">
import { computed, watch, ref, defineProps, defineEmits } from 'vue'
import { RiArrowLeftLine, RiArrowRightLine, RiArrowDownSLine } from '@remixicon/vue'
import { SelectRoot, SelectTrigger, SelectIcon, SelectPortal, SelectContent, SelectViewport, SelectItem, SelectItemText } from 'radix-vue'
import { PaginationProps, EmitsProps } from '@/types'

const props = defineProps<PaginationProps>()

const emit = defineEmits<EmitsProps>()

const pageSizes = computed(() => (props.pageSizes && props.pageSizes.length > 0 ? props.pageSizes : [10, 20, 50, 100]))
const siblingCount = computed(() => (typeof props.siblingCount === 'number' ? props.siblingCount : 1))
const boundaryCount = computed(() => (typeof props.boundaryCount === 'number' ? props.boundaryCount : 1))

const totalPages = computed(() => {
  const size = Math.max(1, props.pageSize)
  const total = Math.max(0, props.total)
  const pages = Math.ceil(total / size)
  return pages > 0 ? pages : 1
})

const page = computed(() => {
  const p = Math.max(1, props.page)
  return Math.min(p, totalPages.value)
})

const range = (start: number, end: number) => Array.from({ length: end - start + 1 }, (_, i) => start + i)

const pages = computed<(number | string)[]>(() => {
  const total = totalPages.value
  const current = page.value
  const siblings = siblingCount.value
  const boundaries = boundaryCount.value

  if (total <= 1) return [1]

  const startPages = range(1, Math.min(boundaries, total))
  const endPages = range(Math.max(total - boundaries + 1, boundaries + 1), total)

  const siblingsStart = Math.max(
    Math.min(current - siblings, total - boundaries - siblings * 2 - 1),
    boundaries + 2
  )
  const siblingsEnd = Math.min(
    Math.max(current + siblings, boundaries + siblings * 2 + 2),
    endPages.length > 0 ? endPages[0] - 2 : total - 1
  )

  const middlePages = siblingsStart <= siblingsEnd ? range(siblingsStart, siblingsEnd) : []

  const items: (number | string)[] = [...startPages]
  if (middlePages.length && startPages[startPages.length - 1] + 1 < middlePages[0]) items.push('…')
  items.push(...middlePages)
  if (endPages.length && middlePages[middlePages.length - 1] + 1 < endPages[0]) items.push('…')
  items.push(...endPages)
  return items
})

const jumpValue = ref<number>(page.value)

const go = (p: number) => {
  const target = Math.max(1, Math.min(p, totalPages.value))
  if (target !== props.page) {
    emit('update:page', target)
    emit('pageChange', target)
  }
  jumpValue.value = target
}

const onJump = () => {
  go(jumpValue.value)
}

const onPageSizeChange = (val: string) => {
  const size = Number(val)
  if (size && size !== props.pageSize) {
    emit('update:pageSize', size)
    emit('pageSizeChange', size)
    emit('update:page', 1)
    emit('pageChange', 1)
    jumpValue.value = 1
  }
}

watch(
  () => props.page,
  (p) => {
    const target = Math.max(1, Math.min(p, totalPages.value))
    jumpValue.value = target
  }
)

</script>

<style></style>
