<script setup>
import { computed, ref, watch } from "vue";
import { useNamespace, useLocale } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { paginationProps } from "./pagination";
import { YhInput } from "../../input";
import { YhSelect, YhOption } from "../../select";
defineOptions({
  name: "YhPagination"
});
const props = defineProps(paginationProps);
const emit = defineEmits(["update:currentPage", "update:pageSize", "current-change", "size-change", "prev-click", "next-click"]);
const ns = useNamespace("pagination");
const { t } = useLocale();
const { themeStyle } = useComponentTheme(
  "pagination",
  computed(() => props.themeOverrides)
);
const pageCount = computed(() => {
  if (props.total > 0) {
    return Math.max(1, Math.ceil(props.total / props.pageSize));
  }
  return 1;
});
const internalCurrentPage = ref(props.currentPage);
watch(
  () => props.currentPage,
  (val) => {
    internalCurrentPage.value = val;
  }
);
const pagers = computed(() => {
  const count = props.pagerCount;
  const currentPage = internalCurrentPage.value;
  const totalPages = pageCount.value;
  const showPrevMore = totalPages > count && currentPage > count - (count - 1) / 2;
  const showNextMore = totalPages > count && currentPage < totalPages - (count - 1) / 2;
  const array = [];
  if (showPrevMore && !showNextMore) {
    const startPage = totalPages - (count - 2);
    for (let i = startPage; i < totalPages; i++) {
      array.push(i);
    }
  } else if (!showPrevMore && showNextMore) {
    for (let i = 2; i < count; i++) {
      array.push(i);
    }
  } else if (showPrevMore && showNextMore) {
    const offset = Math.floor(count / 2) - 1;
    for (let i = currentPage - offset; i <= currentPage + offset; i++) {
      array.push(i);
    }
  } else {
    for (let i = 2; i < totalPages; i++) {
      array.push(i);
    }
  }
  return {
    showPrevMore,
    showNextMore,
    array
  };
});
const handleCurrentChange = (val) => {
  if (props.disabled || val < 1 || val > pageCount.value || val === internalCurrentPage.value)
    return;
  internalCurrentPage.value = val;
  emit("update:currentPage", val);
  emit("current-change", val);
};
const handlePrev = () => {
  if (internalCurrentPage.value <= 1) return;
  const val = internalCurrentPage.value - 1;
  handleCurrentChange(val);
  emit("prev-click", val);
};
const handleNext = () => {
  if (internalCurrentPage.value >= pageCount.value) return;
  const val = internalCurrentPage.value + 1;
  handleCurrentChange(val);
  emit("next-click", val);
};
const handleSizeChange = (val) => {
  emit("update:pageSize", val);
  emit("size-change", val);
};
const jumpValue = ref(internalCurrentPage.value);
watch(internalCurrentPage, (val) => {
  jumpValue.value = val;
});
const handleJump = () => {
  let val = Number(jumpValue.value);
  if (isNaN(val)) val = internalCurrentPage.value;
  val = Math.max(1, Math.min(pageCount.value, Math.floor(val)));
  handleCurrentChange(val);
  jumpValue.value = val;
};
const paginationClasses = computed(() => [
  ns.b(),
  ns.is("background", props.background),
  ns.is("small", props.small),
  ns.is("circle", props.circle),
  ns.is("disabled", props.disabled)
]);
const layoutComponents = computed(() => {
  return props.layout.split(",").map((item) => item.trim());
});
defineExpose({
  currentPage: computed({
    get: () => internalCurrentPage.value,
    set: (val) => {
      internalCurrentPage.value = val;
    }
  }),
  pageSize: computed(() => props.pageSize),
  pageCount: computed(() => pageCount.value)
});
</script>

<template>
  <nav v-if="!hideOnSinglePage || pageCount > 1" :class="paginationClasses" :style="themeStyle">
    <template v-for="item in layoutComponents" :key="item">
      <!-- Total -->
      <span v-if="item === 'total'" :class="ns.e('total')">
        {{ t('pagination.total', { total }) }}
      </span>

      <!-- Sizes -->
      <div v-if="item === 'sizes'" :class="ns.e('sizes')">
        <YhSelect
          :model-value="pageSize"
          :disabled="disabled"
          :size="small ? 'small' : 'default'"
          @update:model-value="val => handleSizeChange(Number(val))"
        >
          <YhOption
            v-for="size in pageSizes"
            :key="size"
            :label="`${size}${t('pagination.pageSize')}`"
            :value="size"
          />
        </YhSelect>
      </div>

      <!-- Prev -->
      <button
        v-if="item === 'prev'"
        :class="ns.e('prev')"
        :disabled="disabled || internalCurrentPage <= 1"
        @click="handlePrev"
      >
        <slot name="prev-icon">
          <span v-if="prevText">{{ prevText }}</span>
          <svg v-else viewBox="0 0 1024 1024" width="1em" height="1em">
            <path
              fill="currentColor"
              d="M609.4 824.6L296.8 512l312.6-312.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L228.9 489.4c-12.5 12.5-12.5 32.8 0 45.3l335.2 335.2c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3z"
            />
          </svg>
        </slot>
      </button>

      <!-- Pager -->
      <ul v-if="item === 'pager'" :class="ns.e('pager')">
        <li
          :class="[ns.e('item'), ns.is('active', internalCurrentPage === 1)]"
          @click="handleCurrentChange(1)"
        >
          1
        </li>

        <li
          v-if="pagers.showPrevMore"
          :class="[ns.e('item'), ns.e('more')]"
          @click="handleCurrentChange(Math.max(1, internalCurrentPage - 5))"
        >
          <span :class="ns.e('more-icon')">...</span>
        </li>

        <li
          v-for="page in pagers.array"
          :key="page"
          :class="[ns.e('item'), ns.is('active', internalCurrentPage === page)]"
          @click="handleCurrentChange(page)"
        >
          {{ page }}
        </li>

        <li
          v-if="pagers.showNextMore"
          :class="[ns.e('item'), ns.e('more')]"
          @click="handleCurrentChange(Math.min(pageCount, internalCurrentPage + 5))"
        >
          <span :class="ns.e('more-icon')">...</span>
        </li>

        <li
          v-if="pageCount > 1"
          :class="[ns.e('item'), ns.is('active', internalCurrentPage === pageCount)]"
          @click="handleCurrentChange(pageCount)"
        >
          {{ pageCount }}
        </li>
      </ul>

      <!-- Next -->
      <button
        v-if="item === 'next'"
        :class="ns.e('next')"
        :disabled="disabled || internalCurrentPage >= pageCount"
        @click="handleNext"
      >
        <slot name="next-icon">
          <span v-if="nextText">{{ nextText }}</span>
          <svg v-else viewBox="0 0 1024 1024" width="1em" height="1em">
            <path
              fill="currentColor"
              d="M341.3 824.6l312.6-312.6L341.3 199.4c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L721.8 489.4c12.5 12.5 12.5 32.8 0 45.3L386.6 869.9c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3z"
            />
          </svg>
        </slot>
      </button>

      <!-- Jumper -->
      <div v-if="item === 'jumper'" :class="ns.e('jumper')">
        {{ t("pagination.goto") }}
        <YhInput
          v-model="jumpValue"
          :size="small ? 'small' : 'default'"
          :disabled="disabled"
          @blur="handleJump"
          @keyup.enter="handleJump"
        />
        {{ t("pagination.page") }}
      </div>

      <!-- Slot -->
      <slot v-if="item === 'slot'" />
    </template>
  </nav>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-pagination {
  --yh-pagination-font-size: 14px;
  --yh-pagination-bg-color: transparent;
  --yh-pagination-text-color: var(--yh-text-color-regular);
  --yh-pagination-border-radius: 2px;
  --yh-pagination-btn-width: 32px;
  --yh-pagination-btn-height: 32px;
  --yh-pagination-btn-bg-color: transparent;
  --yh-pagination-btn-hover-color: var(--yh-color-primary);
  --yh-pagination-item-active-bg-color: var(--yh-color-primary);
  --yh-pagination-item-active-color: #ffffff;
  --yh-pagination-jumper-input-width: 50px;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  color: var(--yh-pagination-text-color);
  font-size: var(--yh-pagination-font-size);
  user-select: none;
  gap: 8px;
  row-gap: 6px;
  box-sizing: border-box;
  vertical-align: middle;
  line-height: 1;
}
.yh-pagination, .yh-pagination * {
  box-sizing: border-box;
}
.yh-pagination.is-small {
  --yh-pagination-font-size: 12px;
  --yh-pagination-btn-width: 24px;
  --yh-pagination-btn-height: 24px;
  --yh-pagination-jumper-input-width: 42px;
  gap: 4px;
}
.yh-pagination__total {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  font-weight: normal;
  color: var(--yh-text-color-regular);
  height: var(--yh-pagination-btn-height);
  white-space: nowrap;
  vertical-align: middle;
  flex-shrink: 0;
}

.yh-pagination__sizes {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  height: var(--yh-pagination-btn-height);
  vertical-align: middle;
  flex-shrink: 0;
}
.yh-pagination__sizes .yh-select {
  width: 110px;
  margin: 0 !important;
}

.yh-pagination__pager {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
  list-style: none;
  gap: 8px;
  height: var(--yh-pagination-btn-height);
  flex-shrink: 0;
}

.yh-pagination__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--yh-pagination-btn-width);
  height: var(--yh-pagination-btn-height);
  margin: 0;
  padding: 0 4px;
  background-color: var(--yh-pagination-btn-bg-color);
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: var(--yh-pagination-border-radius);
  cursor: pointer;
  font-weight: normal;
  transition: all 0.2s;
  color: inherit;
  box-sizing: border-box;
  line-height: normal;
  flex-shrink: 0;
}
.yh-pagination__item:hover {
  color: var(--yh-pagination-btn-hover-color);
  border-color: var(--yh-pagination-btn-hover-color);
}
.yh-pagination__item.is-active {
  color: var(--yh-pagination-item-active-color);
  background-color: var(--yh-pagination-item-active-bg-color);
  border-color: var(--yh-pagination-item-active-bg-color);
  font-weight: bold;
  cursor: default;
}

.yh-pagination__more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--yh-pagination-btn-width);
  height: var(--yh-pagination-btn-height);
  margin: 0;
  padding: 0;
  font-weight: bold;
  color: var(--yh-text-color-secondary);
  cursor: pointer;
  line-height: 1;
  flex-shrink: 0;
}

.yh-pagination__jumper {
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  margin: 0;
  padding: 0;
  gap: 8px;
  height: var(--yh-pagination-btn-height);
  color: var(--yh-text-color-regular);
  white-space: nowrap;
  vertical-align: middle;
  flex-shrink: 0;
}
.yh-pagination__jumper .yh-input {
  width: var(--yh-pagination-jumper-input-width) !important;
  min-width: var(--yh-pagination-jumper-input-width);
  flex: 0 0 var(--yh-pagination-jumper-input-width);
  display: inline-flex;
  align-items: center;
  margin: 0 4px !important;
}
.yh-pagination__jumper .yh-input .yh-input__wrapper {
  min-height: var(--yh-pagination-btn-height);
  padding: 0 6px;
}
.yh-pagination__jumper .yh-input .yh-input__inner {
  padding: 0 !important;
  text-align: center;
  height: calc(var(--yh-pagination-btn-height) - 2px);
  line-height: calc(var(--yh-pagination-btn-height) - 2px);
}

.yh-pagination .yh-select,
.yh-pagination .yh-input,
.yh-pagination .yh-button {
  margin: 0 !important;
  vertical-align: middle;
}
.yh-pagination .yh-pagination__prev, .yh-pagination .yh-pagination__next {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--yh-pagination-btn-width);
  height: var(--yh-pagination-btn-height);
  margin: 0;
  padding: 0;
  background-color: var(--yh-pagination-btn-bg-color);
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: var(--yh-pagination-border-radius);
  cursor: pointer;
  color: inherit;
  transition: all 0.2s;
  line-height: 1;
}
.yh-pagination .yh-pagination__prev svg, .yh-pagination .yh-pagination__next svg {
  display: block;
  width: 14px;
  height: 14px;
  margin: 0;
}
.yh-pagination .yh-pagination__prev:hover:not(:disabled), .yh-pagination .yh-pagination__next:hover:not(:disabled) {
  color: var(--yh-pagination-btn-hover-color);
  border-color: var(--yh-pagination-btn-hover-color);
}
.yh-pagination .yh-pagination__prev:disabled, .yh-pagination .yh-pagination__next:disabled {
  color: var(--yh-text-color-placeholder);
  background-color: var(--yh-fill-color-light);
  cursor: not-allowed;
}
.yh-pagination:not(.is-background) .yh-pagination__item {
  background-color: transparent;
  border: 1px solid var(--yh-border-color-lighter);
  color: var(--yh-text-color-regular);
}
.yh-pagination:not(.is-background) .yh-pagination__item:not(.is-active):hover {
  color: var(--yh-pagination-btn-hover-color);
  border-color: var(--yh-pagination-btn-hover-color);
}
.yh-pagination:not(.is-background) .yh-pagination__item.is-active {
  color: var(--yh-color-primary);
  border-color: var(--yh-color-primary);
  background-color: transparent;
  font-weight: bold;
  cursor: default;
}

.yh-pagination:not(.is-background) .yh-pagination__prev, .yh-pagination:not(.is-background) .yh-pagination__next {
  background-color: transparent;
  border: 1px solid var(--yh-border-color-lighter);
}
.yh-pagination:not(.is-background) .yh-pagination__prev:not(:disabled):hover, .yh-pagination:not(.is-background) .yh-pagination__next:not(:disabled):hover {
  color: var(--yh-pagination-btn-hover-color);
  border-color: var(--yh-pagination-btn-hover-color);
}
.yh-pagination.is-background .yh-pagination__item {
  background-color: var(--yh-fill-color-light);
  border: none;
  color: var(--yh-text-color-regular);
}
.yh-pagination.is-background .yh-pagination__item:not(.is-active):hover {
  background-color: var(--yh-fill-color-darker);
  color: var(--yh-color-primary);
}
.yh-pagination.is-background .yh-pagination__item.is-active {
  background-color: var(--yh-pagination-item-active-bg-color);
  color: #ffffff;
  border: none;
  font-weight: bold;
  cursor: default;
}

.yh-pagination.is-background .yh-pagination__prev, .yh-pagination.is-background .yh-pagination__next {
  background-color: var(--yh-fill-color-light);
  border: none;
}
.yh-pagination.is-background .yh-pagination__prev:not(:disabled):hover, .yh-pagination.is-background .yh-pagination__next:not(:disabled):hover {
  background-color: var(--yh-fill-color-darker);
  color: var(--yh-pagination-btn-hover-color);
}

.yh-pagination.is-background .yh-pagination__more {
  background-color: var(--yh-fill-color-light);
  border-radius: var(--yh-pagination-border-radius);
}

.yh-pagination.is-circle .yh-pagination__item, .yh-pagination.is-circle .yh-pagination__prev, .yh-pagination.is-circle .yh-pagination__next {
  border-radius: 50% !important;
}

.yh-pagination.is-disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.yh-pagination.is-disabled .yh-pagination__item, .yh-pagination.is-disabled .yh-pagination__prev, .yh-pagination.is-disabled .yh-pagination__next, .yh-pagination.is-disabled .yh-pagination__more {
  cursor: not-allowed !important;
}
</style>
