<template>
  <div class="vm-crud-pagination">
    <span class="vm-crud-pagination__total">{{ totalText }}</span>
    <div class="vm-crud-pagination__actions">
      <Select
        :model-value="String(crud.pagination.value.size)"
        @update:model-value="changeSize"
      >
        <SelectTrigger class="vm-crud-pagination__size">
          <SelectValue />
        </SelectTrigger>
        <SelectContent>
          <SelectItem v-for="n in pageSizes" :key="n" :value="String(n)">
            {{ pageSizeText(n) }}
          </SelectItem>
        </SelectContent>
      </Select>
      <button
        type="button"
        class="vm-crud-pagination__btn"
        :disabled="crud.pagination.value.page <= 1"
        @click="go(crud.pagination.value.page - 1)"
      >
        {{ crudLabel('prevPage', crud.dict.label) }}
      </button>
      <div class="vm-crud-pagination__page">
        <input
          v-model="jumpDraft"
          class="vm-crud-pagination__page-input"
          type="text"
          inputmode="numeric"
          autocomplete="off"
          :aria-label="crudLabel('jumpPage', crud.dict.label)"
          @keydown.enter.prevent="jumpToPage"
          @blur="onJumpBlur"
        />
        <span class="vm-crud-pagination__page-sep">/</span>
        <span class="vm-crud-pagination__page-total">{{ totalPages }}</span>
      </div>
      <button
        type="button"
        class="vm-crud-pagination__btn"
        :disabled="crud.pagination.value.page >= totalPages"
        @click="go(crud.pagination.value.page + 1)"
      >
        {{ crudLabel('nextPage', crud.dict.label) }}
      </button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useCrud } from './useCrud'
import { crudFormat, crudLabel } from './style'

defineOptions({ name: 'vm-pagination' })

const crud = useCrud()
const pageSizes = [10, 20, 50, 100]
const jumpDraft = ref('1')

const totalPages = computed(() =>
  Math.max(1, Math.ceil(crud.pagination.value.total / crud.pagination.value.size) || 1),
)

const totalText = computed(() =>
  crudFormat(crudLabel('total', crud.dict.label), crud.pagination.value.total),
)

watch(
  () => crud.pagination.value.page,
  (p) => {
    jumpDraft.value = String(p)
  },
  { immediate: true },
)

function pageSizeText(n: number) {
  return crudFormat(crudLabel('pageSize', crud.dict.label), n)
}

function go(page: number) {
  const next = Math.min(Math.max(1, page), totalPages.value)
  jumpDraft.value = String(next)
  crud.pagination.value = { ...crud.pagination.value, page: next }
  void crud.refresh()
}

function jumpToPage() {
  const n = Number.parseInt(String(jumpDraft.value || '').trim(), 10)
  if (!Number.isFinite(n)) {
    jumpDraft.value = String(crud.pagination.value.page)
    return
  }
  go(n)
}

function onJumpBlur() {
  const cur = crud.pagination.value.page
  const n = Number.parseInt(String(jumpDraft.value || '').trim(), 10)
  if (!Number.isFinite(n) || n === cur) {
    jumpDraft.value = String(cur)
    return
  }
  go(n)
}

function changeSize(size: unknown) {
  crud.pagination.value = {
    ...crud.pagination.value,
    size: Number(size),
    page: 1,
  }
  jumpDraft.value = '1'
  void crud.refresh()
}
</script>

<style lang="scss" scoped>
.vm-crud-pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding-top: 8px;
  border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
  color: var(--muted-foreground);
  font-size: 12px;
}

.vm-crud-pagination__actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

:deep(.vm-crud-pagination__size) {
  height: 34px !important;
  width: 96px;
  border: none !important;
  border-radius: 12px !important;
  background: var(--muted) !important;
  box-shadow: none !important;
}

.vm-crud-pagination__btn {
  height: 34px;
  padding: 0 12px;
  border: none;
  border-radius: 12px;
  background: var(--muted);
  color: var(--foreground);
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;

  &:hover:not(:disabled) {
    background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
  }

  &:disabled {
    cursor: not-allowed;
    opacity: 0.4;
  }
}

.vm-crud-pagination__page {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 56px;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--foreground) 80%, transparent);
}

.vm-crud-pagination__page-input {
  box-sizing: border-box;
  width: 2.75em;
  height: 34px;
  padding: 0 4px;
  border: none;
  border-radius: 12px;
  background: var(--muted);
  color: var(--foreground);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
  appearance: none;
  -webkit-appearance: none;

  &:focus {
    outline: none;
    background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
    box-shadow: none;
  }
}

.vm-crud-pagination__page-sep,
.vm-crud-pagination__page-total {
  flex: none;
  line-height: 1;
}
</style>
