import { makeComponentProps } from '@/composables/component'
import { makeTagProps } from '@/composables/tag'
import { genericComponent, propsFactory, useRender } from '@/utils'
import { ExtractPropTypes, PropType, ref, computed, onMounted } from 'vue'
import UntitledColorTypes from '@/types/untitledColorTypes'
import { UButton } from '@/components'
import { UPaginationNumber } from '@/components'
import { useEventListener } from '@vueuse/core'
import { throttle } from '@/utils/throttle'

export const makeUPaginationProps = propsFactory(
  {
    modelValue: {
      type: String,
      default: '0',
      required: false,
    },
    type: {
      type: String,
      default: 'default',
      required: false,
    },
    shape: {
      type: String,
      default: 'square',
      required: false,
    },
    align: {
      type: [String, undefined] as PropType<string | undefined>,
      required: false,
    },
    pagesCount: {
      type: String,
      default: '0',
      required: false,
    },
    ...makeComponentProps(),
    ...makeTagProps(),
  },
  'UPagination'
)

export type UPaginationProps = ExtractPropTypes<typeof makeUPaginationProps>

export const UPagination = genericComponent()({
  name: 'UPagination',

  props: makeUPaginationProps(),

  emits: {
    change: (value: number) => true,
    'update:modelValue': (value: string) => true,
  },

  setup(props, { emit }) {
    const isMinimalPagination = ref(false)
    const containerWidth = ref(0)
    const paginationContainer = ref<HTMLElement | null>(null)
    const containerWidthBreakPoint = 640
    const count = parseInt(props.pagesCount, 10)
    const numbers = Array.from(Array(count), (_, index) => index + 1)

    const updateActivePage = (pageNumber: number) => {
      emit('change', pageNumber)
      emit('update:modelValue', pageNumber.toString())
    }

    const activePageIndex = computed(() => {
      return parseInt(props.modelValue, 10)
    })

    const getDisplayedPages = computed(() => {
      if (count <= 6) {
        return numbers
      }

      const centralPage = count / 2
      let displayedLeftPages: number[] = []
      let displayedRightPages: number[] = []

      if (activePageIndex.value >= centralPage) {
        displayedLeftPages = numbers.slice(0, 3)
        displayedRightPages = [
          numbers[activePageIndex.value - 2],
          numbers[activePageIndex.value - 1],
          numbers[activePageIndex.value],
        ]
      } else if (activePageIndex.value < centralPage) {
        displayedLeftPages = [
          numbers[activePageIndex.value - 2],
          numbers[activePageIndex.value - 1],
          numbers[activePageIndex.value],
        ]
        displayedRightPages = numbers.slice(-3)
      }

      if (activePageIndex.value === 1) {
        displayedLeftPages = numbers.slice(0, 3)
      }

      if (activePageIndex.value === count) {
        displayedRightPages = numbers.slice(-3)
      }

      return [...displayedLeftPages, '...', ...displayedRightPages]
    })

    const goToPreviousPage = () => {
      if (activePageIndex.value) {
        updateActivePage(activePageIndex.value - 1)
      }
    }

    const goToNextPage = () => {
      const pageCount = parseInt(props.pagesCount, 10)
      if (activePageIndex.value < pageCount) {
        updateActivePage(activePageIndex.value + 1)
      }
    }

    const updateContainerWidth = () => {
      console.log('Called!')
      if (!paginationContainer.value) {
        return false
      }

      const computedStyle = getComputedStyle(paginationContainer.value)
      const margin =
        parseFloat(computedStyle.marginLeft) +
        parseFloat(computedStyle.marginRight)
      containerWidth.value = paginationContainer.value.clientWidth + margin

      isMinimalPagination.value =
        containerWidth.value <= containerWidthBreakPoint
    }

    onMounted(() => {
      updateContainerWidth()
    })

    useEventListener(window, 'resize', throttle(updateContainerWidth, 100))

    const alignClasses = computed(() => ({
      ['left-0']: props.align === 'left',
      ['right-0']: props.align === 'right',
      ['transform left-1/2 transform -translate-x-1/2']:
        props.align === 'center' ||
        props.align === undefined ||
        isMinimalPagination.value,
    }))

    const prependButtonClasses = computed(() => ({
      ['absolute']: props.align === 'left' || props.align === 'right',
      ['left-0']: props.align === 'right',
      ['right-72']: props.align === 'left',
    }))

    const buttonType = computed(() => {
      return props.type === 'default' && !isMinimalPagination.value
        ? UntitledColorTypes.linkGray
        : UntitledColorTypes.secondaryGray
    })

    const appendButtonClasses = computed(() => ({
      ['absolute']: props.align === 'left' || props.align === 'right',
      ['left-99']: props.align === 'right',
      ['right-0']: props.align === 'left',
    }))

    useRender(() => {
      return (
        <div ref={paginationContainer} class={[props.class, 'relative']}>
          <div class="w-full flex justify-between items-center">
            <div class={prependButtonClasses.value}>
              <UButton
                class="previous"
                prependIcon={
                  props.type === 'default' ||
                  (props.type === 'minimal' && props.align === undefined) ||
                  isMinimalPagination.value
                    ? 'arrowLeft'
                    : ''
                }
                type={buttonType.value}
                onClick={goToPreviousPage}
              >
                {!isMinimalPagination.value ? 'Previous' : null}
              </UButton>
            </div>

            {(props.align === undefined || props.align === 'center') &&
            !isMinimalPagination.value ? (
              <div class="w-fit flex justify-center gap-0 items-center">
                {getDisplayedPages.value.map((page, index) => (
                  <UPaginationNumber
                    key={index}
                    shape={props.shape}
                    is-active={page === numbers[activePageIndex.value - 1]}
                    onClick={() => updateActivePage(page as number)}
                    class={page === '...' ? 'pointer-events-none' : ''}
                  >
                    {page}
                  </UPaginationNumber>
                ))}
              </div>
            ) : null}
            {props.align === 'left' ||
            props.align === 'right' ||
            isMinimalPagination.value ? (
              <div
                class={[
                  alignClasses.value,
                  'absolute text-text-sm text-gray-700 font-medium',
                ]}
              >
                {'Page ' +
                  (activePageIndex.value + 1) +
                  ' of ' +
                  props.pagesCount}
              </div>
            ) : null}

            <div class={appendButtonClasses.value}>
              <UButton
                class="next"
                appendIcon={
                  props.type === 'default' ||
                  (props.type === 'minimal' && props.align === undefined) ||
                  isMinimalPagination.value
                    ? 'arrowRight'
                    : ''
                }
                type={buttonType.value}
                onClick={goToNextPage}
              >
                {!isMinimalPagination.value ? 'Next' : null}
              </UButton>
            </div>
          </div>
        </div>
      )
    })

    return {
      count,
      updateActivePage,
      goToNextPage,
      goToPreviousPage,
    }
  },
})

export type UPagination = InstanceType<typeof UPagination>
