<script setup lang="ts" generic="T">
import type { Table } from '@tanstack/vue-table'

import {
  ChevronLeftIcon,
  ChevronRightIcon,
  ChevronsLeft,
  ChevronsRight,
} from 'lucide-vue-next'
import { useI18n } from 'vue-i18n'

import { PAGE_SIZES } from '@/constants/pagination'

import type { ServerPagination } from './types'

interface DataTablePaginationProps {
  table: Table<T>
  serverPagination?: ServerPagination
}

const props = defineProps<DataTablePaginationProps>()
const { t } = useI18n()

const isServerPagination = computed(() => !!props.serverPagination)

const currentPage = computed(() => {
  if (isServerPagination.value && props.serverPagination) {
    return props.serverPagination.page
  }
  return props.table.getState().pagination.pageIndex + 1
})

const currentPageSize = computed(() => {
  if (isServerPagination.value && props.serverPagination) {
    return props.serverPagination.pageSize
  }
  return props.table.getState().pagination.pageSize
})

const totalPages = computed(() => {
  if (isServerPagination.value && props.serverPagination) {
    return Math.ceil(props.serverPagination.total / props.serverPagination.pageSize)
  }
  return props.table.getPageCount()
})

const canPreviousPage = computed(() => {
  if (isServerPagination.value) {
    return currentPage.value > 1
  }
  return props.table.getCanPreviousPage()
})

const canNextPage = computed(() => {
  if (isServerPagination.value) {
    return currentPage.value < totalPages.value
  }
  return props.table.getCanNextPage()
})

const selectedCount = computed(() => props.table.getSelectedRowModel().rows.length)

const jumpPage = ref<string>('')
const isEditingPage = ref(false)

function handlePageSizeChange(value: any) {
  if (!value)
    return
  const newPageSize = Number(value)
  if (isServerPagination.value && props.serverPagination?.onPageSizeChange) {
    props.serverPagination.onPageSizeChange(newPageSize)
  }
  else {
    props.table.setPageSize(newPageSize)
  }
}

function goToFirstPage() {
  if (isServerPagination.value && props.serverPagination?.onPageChange) {
    props.serverPagination.onPageChange(1)
  }
  else {
    props.table.setPageIndex(0)
  }
}

function goToPreviousPage() {
  if (isServerPagination.value && props.serverPagination?.onPageChange) {
    props.serverPagination.onPageChange(currentPage.value - 1)
  }
  else {
    props.table.previousPage()
  }
}

function goToNextPage() {
  if (isServerPagination.value && props.serverPagination?.onPageChange) {
    props.serverPagination.onPageChange(currentPage.value + 1)
  }
  else {
    props.table.nextPage()
  }
}

function goToLastPage() {
  if (isServerPagination.value && props.serverPagination?.onPageChange) {
    props.serverPagination.onPageChange(totalPages.value)
  }
  else {
    props.table.setPageIndex(props.table.getPageCount() - 1)
  }
}

function startEditPage() {
  jumpPage.value = String(currentPage.value)
  isEditingPage.value = true
}

function handleJumpPage() {
  const page = Number.parseInt(jumpPage.value, 10)
  if (!Number.isNaN(page) && page >= 1 && page <= totalPages.value) {
    if (isServerPagination.value && props.serverPagination?.onPageChange) {
      props.serverPagination.onPageChange(page)
    }
    else {
      props.table.setPageIndex(page - 1)
    }
  }
  isEditingPage.value = false
  jumpPage.value = ''
}
</script>

<template>
  <div class="flex items-center justify-between px-2">
    <div class="flex items-center text-sm text-muted-foreground">
      <Transition
        enter-active-class="transition-all duration-200 ease-out"
        leave-active-class="transition-all duration-200 ease-in"
        enter-from-class="opacity-0"
        leave-to-class="opacity-0"
      >
        <span v-if="selectedCount">
          {{ selectedCount }} {{ t('common.itemsSelected') }}
        </span>
      </Transition>
    </div>
    <div class="flex items-center gap-4">
      <div class="flex items-center gap-2">
        <span class="text-sm text-muted-foreground">{{ t('common.rowsPerPage') }}</span>
        <UiSelect
          :model-value="`${currentPageSize}`"
          @update:model-value="handlePageSizeChange"
        >
          <UiSelectTrigger size="sm" class="h-7 w-[65px] px-2">
            <UiSelectValue :placeholder="`${currentPageSize}`" />
          </UiSelectTrigger>
          <UiSelectContent side="top">
            <UiSelectItem v-for="pageSize in PAGE_SIZES" :key="pageSize" :value="`${pageSize}`">
              {{ pageSize }}
            </UiSelectItem>
          </UiSelectContent>
        </UiSelect>
      </div>
      <div class="flex items-center gap-1">
        <UiButton
          variant="outline"
          class="size-8 p-0"
          :disabled="!canPreviousPage"
          @click="goToFirstPage"
        >
          <ChevronsLeft class="size-4" />
        </UiButton>
        <UiButton
          variant="outline"
          class="size-8 p-0"
          :disabled="!canPreviousPage"
          @click="goToPreviousPage"
        >
          <ChevronLeftIcon class="size-4" />
        </UiButton>
        <div class="flex items-center px-2">
          <template v-if="isEditingPage">
            <UiInput
              v-model="jumpPage"
              inputmode="numeric"
              pattern="[0-9]*"
              class="h-7 w-14 text-center text-sm [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
              @blur="handleJumpPage"
              @keydown.enter="handleJumpPage"
              @keydown.escape="isEditingPage = false"
            />
            <span class="ml-1 text-sm">/ {{ totalPages }}</span>
          </template>
          <button
            v-else
            class="min-w-[60px] rounded px-2 py-1 text-sm font-medium hover:bg-accent"
            @click="startEditPage"
          >
            {{ currentPage }} / {{ totalPages }}
          </button>
        </div>
        <UiButton
          variant="outline"
          class="size-8 p-0"
          :disabled="!canNextPage"
          @click="goToNextPage"
        >
          <ChevronRightIcon class="size-4" />
        </UiButton>
        <UiButton
          variant="outline"
          class="size-8 p-0"
          :disabled="!canNextPage"
          @click="goToLastPage"
        >
          <ChevronsRight class="size-4" />
        </UiButton>
      </div>
    </div>
  </div>
</template>
