<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useAttrsWithDefaults } from '../../composables/useAttrsWithDefaults'
import { debounce } from '../../helpers/debounce'
import { useFdsI18n } from '../../plugin/useFdsI18n'
import FdsButtonIcon from '../Buttons/FdsButtonIcon/FdsButtonIcon.vue'
import FdsSpinner from '../FdsSpinner/FdsSpinner.vue'
import FdsInput from '../Form/FdsInput/FdsInput.vue'
import type { FdsPaginationProps } from './types'

const props = withDefaults(defineProps<FdsPaginationProps>(), {
  loading: false,
  dataTestid: undefined,
})

const { id } = useAttrsWithDefaults(props)
const { t } = useFdsI18n()

const emit = defineEmits<{
  (e: 'paginate', payload: { target: { id: string }; detail: number }): void
}>()

const loadingIndicator = ref<'start' | 'prev' | 'input' | 'next' | 'end' | ''>('')
const internalValue = ref(props.current)

const autoId = `fds-pagination-${Math.random().toString(36).slice(2, 9)}`
const inputId = computed(() => id.value ?? autoId)

const rootAttrs = computed(() => {
  const attrs: Record<string, string> = {}
  if (props.dataTestid) {
    attrs['data-testid'] = props.dataTestid
  }
  return attrs
})

const inputValue = computed(() => String(internalValue.value))

const nextPageLabel = computed(() => t('FdsPagination.nextPage'))
const prevPageLabel = computed(() => t('FdsPagination.previousPage'))
const firstPageLabel = computed(() => t('FdsPagination.firstPage'))
const lastPageLabel = computed(() => t('FdsPagination.lastPage'))
const inputAriaLabel = computed(() => t('FdsPagination.currentPage'))
const loadingLabel = computed(() => t('FdsPagination.loading'))

watch(
  () => props.current,
  (newValue) => {
    internalValue.value = newValue
  },
)

const handlePageChange = debounce((event: Event) => {
  const target = event.target as HTMLInputElement
  const incomingPage = Number.parseInt(target.value)

  if (Number.isNaN(incomingPage)) {
    internalValue.value = props.current
    return
  }

  loadingIndicator.value = 'input'

  let page = props.current
  if (incomingPage > props.max) {
    page = props.max
  } else if (incomingPage < 1) {
    page = 1
  } else {
    page = incomingPage
  }

  internalValue.value = page
  emit('paginate', { target: { id: inputId.value }, detail: page })
}, 300)

const handlePagination = (action: 'start' | 'prev' | 'next' | 'end') => {
  let page = 0

  switch (action) {
    case 'start':
      if (props.current === 1) return
      loadingIndicator.value = 'start'
      page = 1
      break
    case 'prev':
      if (props.current === 1) return
      loadingIndicator.value = 'prev'
      page = props.current === 1 ? props.current : props.current - 1
      break
    case 'next':
      if (props.current === props.max) return
      loadingIndicator.value = 'next'
      page = props.current === props.max ? props.current : props.current + 1
      break
    case 'end':
      if (props.current === props.max) return
      loadingIndicator.value = 'end'
      page = props.max
      break
  }

  emit('paginate', { target: { id: inputId.value }, detail: page })
}
</script>

<template>
  <div class="my-6 flex items-between justify-between gap-2" :id="inputId" v-bind="rootAttrs">
    <!-- Prev -->
    <div class="flex items-center justify-start gap-1 w-[100px]">
      <FdsSpinner v-if="loading && loadingIndicator === 'start'" size="32px" color="blue" />
      <FdsButtonIcon
        v-else
        v-bind="{ 'aria-disabled': current === 1 }"
        type="button"
        :aria-label="firstPageLabel"
        icon="first"
        :size="28"
        :disabled="current === 1"
        :class="{ 'hidden!': current === 1 }"
        class="w-8 h-8 sm:w-12 sm:h-12"
        @click="handlePagination('start')"
      />

      <FdsSpinner v-if="loading && loadingIndicator === 'prev'" size="24px" color="blue" />
      <FdsButtonIcon
        v-else
        v-bind="{ 'aria-disabled': current === 1 }"
        type="button"
        :aria-label="prevPageLabel"
        icon="arrowLeft"
        :size="28"
        :disabled="current === 1"
        :class="{ 'hidden!': current === 1 }"
        class="w-8 h-8 sm:w-12 sm:h-12"
        @click="handlePagination('prev')"
      />
    </div>

    <!-- Numbers -->
    <div class="flex items-center justify-center w-auto gap-2 order-0 sm:order-0">
      <FdsSpinner
        v-if="loading && loadingIndicator === 'input'"
        size="24px"
        color="blue"
        :label="loadingLabel"
        label-position="right"
      />
      <template v-else>
        <FdsInput
          style="text-align: center"
          :value="inputValue"
          type="text"
          :size="max.toString().length"
          :maxlength="max.toString().length"
          :ariaLabel="inputAriaLabel"
          @input="handlePageChange"
          class="mb-0!"
        />
        <div class="whitespace-nowrap">/ {{ max }}</div>
      </template>
    </div>

    <!-- Next -->
    <div class="flex items-center justify-end gap-1 order-2 sm:order-0 w-[100px]">
      <FdsSpinner v-if="loading && loadingIndicator === 'next'" size="24px" color="blue" />
      <FdsButtonIcon
        v-else
        type="button"
        :aria-label="nextPageLabel"
        icon="arrowRight"
        :size="28"
        :disabled="current === max"
        v-bind="{ 'aria-disabled': current === max }"
        :class="{ 'hidden!': current === max }"
        class="w-8 h-8 sm:w-12 sm:h-12"
        @click="handlePagination('next')"
      />

      <FdsSpinner v-if="loading && loadingIndicator === 'end'" size="24px" color="blue" />
      <FdsButtonIcon
        v-else
        type="button"
        :aria-label="lastPageLabel"
        icon="last"
        :size="28"
        :disabled="current === max"
        v-bind="{ 'aria-disabled': current === max }"
        :class="{ 'hidden!': current === max }"
        class="w-8 h-8 sm:w-12 sm:h-12"
        @click="handlePagination('end')"
      />
    </div>
  </div>
</template>
