<template>
    <div class="flex" :class="justify">
        <span :class="btnGroupClasses">
            <AisButtonGroup
                :aria-label="ariaLabel"
                :class="btnGroupClasses"
                name="pagination"
                :rounded="rounded"
            >
              <!-- FIRST -->
              <AisButton v-if="!(hideGotoEndButtons || firstNumber)"
                         :class="[buttonClass, firstClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelFirstPage"
                         @click.prevent="setPage(1)"
              >
                  <!--
                    @slot The "go to first page" button content. Optionally scoped
                  -->
                <span class="align-middle">
                  <slot name="first-text">
                    <template v-if="firstText">{{ firstText }}</template>
                    <AisIcon v-else icon="first" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

              <!-- PREVIOUS -->
              <AisButton :class="[buttonClass, prevClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelPrevPage"
                         @click.prevent="previous"
              >
                  <!--
                    @slot The "go to previous page" button content. Optionally scoped
                  -->
                <span class="align-middle">
                  <slot name="prev-text">
                    <template v-if="prevText">{{ prevText }}</template>
                    <AisIcon v-else icon="left" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

              <!-- FIRST NUMBER -->
              <AisButton v-if="firstNumber"
                         :class="[buttonClass, firstClass, activeClass(1)]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelFirstPage"
                         @click.prevent="setPage(1)"
              ><span class="align-middle">1</span></AisButton>

              <!-- LOWER ELLIPSIS -->
              <AisButton v-if="showFirstEllipsis"
                         class="ellipsis pointer-events-none"
                         :class="[buttonClass, ellipsisClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
              >
                  <!--
                    @slot The '...' indicator content. Not scoped
                  -->
                <span class="align-middle">
                  <slot name="ellipsis-text">
                    <template v-if="ellipsisText">{{ ellipsisText }}</template>
                    <AisIcon v-else :icon="faEllipsisH" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

              <!-- PAGES -->
              <AisButton v-for="page in pages" :key="page"
                         :class="[buttonClass, pageClass, activeClass(page)]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="`${labelPage} ${page}`"
                         @click.prevent="setPage(page)"
              ><span class="align-middle">{{ page }}</span></AisButton>

              <!-- UPPER ELLIPSIS -->
              <AisButton v-if="showLastEllipsis"
                         class="ellipsis pointer-events-none"
                         :class="[buttonClass, ellipsisClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
              >
                  <!--
                    @slot The '...' indicator content. Not scoped
                  -->
                <span class="align-middle">
                  <slot name="ellipsis-text">
                    <template v-if="ellipsisText">{{ ellipsisText }}</template>
                    <AisIcon v-else :icon="faEllipsisH" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

              <!-- LAST NUMBER -->
              <AisButton v-if="lastNumber"
                         :class="[buttonClass, lastClass, activeClass(pageCount)]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelLastPage"
                         @click.prevent="setPage(pageCount)"
              ><span class="align-middle">{{ pageCount }}</span></AisButton>

              <!-- NEXT -->
              <AisButton :class="[buttonClass, nextClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelNextPage"
                         @click.prevent="next"
              >
                  <!--
                    @slot The "go to next page" button content. Optionally scoped
                  -->
                <span class="align-middle">
                  <slot name="next-text">
                    <template v-if="nextText">{{ nextText }}</template>
                    <AisIcon v-else icon="right" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

              <!-- LAST -->
              <AisButton v-if="!(hideGotoEndButtons || lastNumber)"
                         :class="[buttonClass, lastClass]"
                         :variant="variant"
                         :size="size"
                         :disabled="disabled"
                         :aria-label="labelLastPage"
                         @click.prevent="setPage(pageCount)"
              >
                  <!--
                    @slot The "go to last page" button content. Optionally scoped
                  -->
                <span class="align-middle">
                  <slot name="last-text">
                    <template v-if="lastText">{{ lastText }}</template>
                    <AisIcon v-else icon="last" class="icon-only"/>
                  </slot>
                </span>
              </AisButton>

            </AisButtonGroup>
        </span>
    </div>
</template>

<script setup>

    import { ref, computed } from "vue";
    import AisButtonGroup from '@/components/button-group/AisButtonGroup.vue'
    import AisButton from '@/components/button/AisButton.vue'
    import AisIcon from '@/components/icon/AisIcon.vue'
    import { expectedValues } from "@/util/prop-validators";
    import { faEllipsisH } from '@fortawesome/free-solid-svg-icons'
    import { library } from '@fortawesome/fontawesome-svg-core'
    library.add( faEllipsisH)

    const ellipsisThreshold = ref(3)
    const showFirstEllipsis = ref(false)
    const showLastEllipsis = ref(false)

    const props = defineProps({
        modelValue: { type: Number, required: false, default: () => 1 },

        /**
         * When set to 'true', disables the component's functionality and places it in a disabled state
         */
        disabled: { type: Boolean, default: false },

        /**
         * Maximum number of buttons to show (including ellipsis if shown, but excluding the bookend buttons)
         */
        limit: { type: [Number, String], default: () => 5 },

        /**
         * Alignment of the page buttons: 'start' (or 'left'), 'center', 'end' (or 'right'), or 'fill'
         */
        align: { type: String, default: () => 'center', validator: expectedValues('start', 'left', 'center', 'end', 'right', 'fill') },

        /**
         * Applies pill styling to the pagination buttons
         */
        pills: { type: Boolean, default: false },

        /**
         * Hides the goto first and goto last page buttons
         */
        hideGotoEndButtons: { type: Boolean, default: false },

        /**
         * Value to place in the 'aria-label' attribute of the pagination control
         */
        ariaLabel: { type: String, default: () => 'Pagination' },

        /**
         * Value to place in the 'aria-label' attribute of the goto first page button
         */
        labelFirstPage: { type: String, default: () => 'Go to first page' },

        /**
         * Content to place in the goto first page button
         */
        firstText: { type: String, default: () => undefined },

        /**
         * Display first page number instead of Goto First button
         */
        firstNumber: { type: Boolean, default: false },

        /**
         * Class(es) to apply to the 'Go to first page' button
         */
        firstClass: { type: [String, Array, Object], default: () => null },

        /**
         * Value to place in the 'aria-label' attribute of the goto previous page button
         */
        labelPrevPage: { type: String, default: () => 'Go to previous page' },

        /**
         * Content to place in the goto previous page button
         */
        prevText: { type: String, default: () => undefined },

        /**
         * Class(es) to apply to the 'Go to previous page' button
         */
        prevClass: { type: [String, Array, Object], default: () => null },

        /**
         * Value to place in the 'aria-label' attribute of the goto next page button
         */
        labelNextPage: { type: String, default: () => 'Go to next page' },

        /**
         * Content to place in the goto next page button
         */
        nextText: { type: String, default: () => undefined },

        /**
         * Class(es) to apply to the 'Go to next page' button
         */
        nextClass: { type: [String, Array, Object], default: () => '' },

        /**
         * Value to place in the 'aria-label' attribute of the goto last page button
         */
        labelLastPage: { type: String, default: () => 'Go to last page' },

        /**
         * Content to place in the goto last page button
         */
        lastText: { type: String, default: () => undefined },

        /**
         * Display last page number instead of Goto Last button
         */
        lastNumber: { type: Boolean, default: () => false },

        /**
         * Class(es) to apply to the 'Go to last page' button
         */
        lastClass: { type: [String, Array, Object], default: () => '' },

        /**
         * Value to place in the 'aria-label' attribute of the goto page button. Page number will be prepended
         * automatically
         */
        labelPage: { type: [String, Function], default: () => 'Go to page' },

        /**
         * Class(es) to apply to the 'Go to page #' buttons
         */
        pageClass: { type: [String, Array, Object], default: () => '' },

        /**
         * Do not show ellipsis buttons
         */
        hideEllipsis: { type: Boolean, default: () => false },

        /**
         * Content to place in the ellipsis placeholder
         */
        ellipsisText: { type: String, default: () => undefined },

        /**
         * Class(es) to apply to the 'ellipsis' placeholders
         */
        ellipsisClass: { type: [String, Array, Object], default: () => '' },

        /**
         * Size of the rendered buttons: 'sm', 'md' (default), or 'lg'
         */
        size: { type: String, default: () => 'sm', validator: expectedValues('xs', 'sm', 'md', 'lg', 'xl') },

        /**
         * Number of rows per page
         */
        perPage: { type: [Number, String], default: () => 10 },

        /**
         * Total number of rows in the dataset
         */
        totalRows: { type: [Number, String], default: () => 0 },

        /**
         * ID of the element or component that this controls. Value is placed in the 'aria-controls' attribute
         */
        ariaControls: { type: String, default: () => '' },

        /**
         * Applies one of the theme color variants to the component.
         */
        variant: { type: String, required: false, default: 'secondary' },


        /**
         * Specifies if the corners are rounded or not
         */
        rounded: { type: [Boolean, String], default: () => false, validator: expectedValues(true, false, 'md', 'lg', 'full') },

    })

    const emit = defineEmits(['update:modelValue', 'input', 'change'])

    /* COMPUTED */
    const localValue = computed({
        get () { return props.modelValue },
        set(val) {
            emit('update:modelValue', val)
            emit('input', val)
            emit('change', val)
        }
    })

    const pageCount = computed(() => Math.ceil(props.totalRows / props.perPage) )
    const justify = computed(() => {
        if(props.align != null) {
            const align = props.align.toUpperCase();
            if (align === 'START' || align === 'LEFT')
                return 'justify-start';
            else if (align === 'END' || align === 'RIGHT')
                return 'justify-end';
            else if (align === 'FILL')
                return '';
        }

        return 'justify-center';
    })
    const btnGroupClasses = computed(() => props.align && props.align.toUpperCase() === 'FILL' ? ['flex', 'flex-1'] : [] )
    const numberOfLinks = computed(() => {
        const count = pageCount.value <= props.limit ? pageCount.value : props.limit;

        return count - (props.firstNumber ? 1 : 0) - (props.lastNumber ? 1 : 0);
    })

    const params =  computed(() => {
        let showFirstEllipsis = false
        let showLastEllipsis = false
        let numberOfLinks = props.limit
        let startNumber = 1

        if(pageCount.value <= props.limit) {
            numberOfLinks = pageCount.value;
        } else if(localValue.value < props.limit - 1 && props.limit > ellipsisThreshold.value) {
            if(!props.hideEllipsis || props.lastNumber) {
                showLastEllipsis = true;
                numberOfLinks = props.limit - (props.firstNumber ? 0 : 1);
            }

            numberOfLinks = Math.min(numberOfLinks, props.limit);
        } else if(pageCount.value - localValue.value + 2 < props.limit && props.limit > ellipsisThreshold.value) {
            if(!props.hideEllipsis || props.firstNumber) {
                showFirstEllipsis = true;
                numberOfLinks = props.limit - (props.lastNumber ? 0 : 1);
            }

            startNumber = pageCount.value - numberOfLinks + 1;
        } else {
            if(props.limit > ellipsisThreshold.value) {
                numberOfLinks = props.limit - (props.hideEllipsis ? 0 : 2);
                showFirstEllipsis = !!(!props.hideEllipsis || props.firstNumber);
                showLastEllipsis = !!(!props.hideEllipsis || props.lastNumber);
            }

            startNumber = localValue.value - Math.floor(numberOfLinks / 2);
        }

        if(startNumber < 1) {
            startNumber = 1;
            showFirstEllipsis = false;
        } else if(startNumber > pageCount.value - numberOfLinks) {
            startNumber = pageCount.value - numberOfLinks + 1;
        }

        if(showFirstEllipsis && props.firstNumber && startNumber < 4) {
            numberOfLinks = numberOfLinks + 2;
            startNumber = 1;
            showFirstEllipsis = false;
        }

        const lastPageNumber = startNumber + numberOfLinks - 1;
        if(showLastEllipsis && props.lastNumber && lastPageNumber > pageCount.value - 3) {
            numberOfLinks = numberOfLinks + (lastPageNumber === pageCount.value - 2 ? 2 : 3);
            showLastEllipsis = false;
        }

        if(props.limit <= ellipsisThreshold.value) {
            if(props.firstNumber && startNumber === 1) {
                numberOfLinks = Math.min(numberOfLinks + 1, pageCount.value, props.limit + 1);
            } else if(props.lastNumber && pageCount.value === startNumber + numberOfLinks - 1) {
                startNumber = Math.max(startNumber - 1, 1);
                numberOfLinks = Math.min(pageCount.value - startNumber + 1, pageCount.value, props.limit + 1);
            }
        }

        numberOfLinks = Math.min(numberOfLinks, pageCount.value - startNumber + 1);

        return { showFirstEllipsis, showLastEllipsis, numberOfLinks, startNumber };
    })

    const pages = computed(() => {
        const { showFirstEllipsis: showFirstEll, showLastEllipsis: showLastEll, numberOfLinks, startNumber } = params.value;
        showFirstEllipsis.value = showFirstEll;
        showLastEllipsis.value = showLastEll;
        return getPages(startNumber, numberOfLinks) || [];
    })

    const buttonClass = computed(() => {
        const classes = [];

        if(props.align && props.align.toUpperCase() === 'FILL')
            classes.push('flex-1');

        return classes.join(' ');
    })

    const overLimit = computed(() => pageCount.value > props.limit )
    const showEllipsis = computed(() => !props.hideEllipsis && props.limit > 3 && overLimit.value )
    const showEllipsisLow = computed(() => showEllipsis.value && localValue.value > 1 )
    const showEllipsisHigh = computed(() => showEllipsis.value )


    /* METHODS */
    const getPages = (startNumber, numberOfPages) => {
        // console.log(`getPages: start=[${startNumber}], numberOfPages=[${numberOfPages}]`);
        const pages = [];
        for(let i = startNumber; i < startNumber + numberOfPages; i++) {
            pages.push(i);
        }

        if(props.firstNumber && !showFirstEllipsis.value) pages.shift();
        if(props.lastNumber && !showLastEllipsis.value) pages.pop();

        // console.log(`getPages: pages=${JSON.stringify(pages)}`);
        return pages;
    }

    const next = () => {
        if(localValue.value < pageCount.value)
            localValue.value = Number(localValue.value) + 1;
    }
    const previous = () => {
        if(localValue.value > 1)
            localValue.value = Number(localValue.value) - 1;
    }
    const setPage = (page) => { localValue.value = page }
    const isActive = (page) => {
        console.log(`isActive:  page=[${page}], localValue=[${localValue.value}], equal=[${localValue.value === page}]`);
        return localValue.value === page;
    }
    const activeClass = (page) => {
        // console.log(`activeClass:  page=[${page}], localValue=[${localValue.value}], equal=[${localValue.value === page}]`);
        return localValue.value === page ? 'active' : '';
    }

</script>

<script>
    export default {
        name: "AisPagination",
    }
</script>