<template>
    <nav
        v-if="totalPages > 1"
        class="c2-pagination"
        aria-label="Pagination"
    >
        <button
            :class="previousBtnClasses"
            @click="goToPreviousPage"
            :disabled="previousPageButtonDisabled"
        >
            <slot name="previous-page-btn" />
        </button>
        <ul 
            :class="listClasses"
        >
            <li
                v-for="(pageNum, index) in visiblePages"
                :key="`pageNum-${index}`"
                :class="listItemClasses" 
                :aria-label="`Page ${pageNum}`"
            >
                <button
                    @click="goToPage(pageNum)"
                    :class="[
                        pageValue === pageNum ? activePageNumberBtnClasses : null,
                        pageNumberBtnClasses
                    ]"
                    :disabled="pageValue === pageNum"
                    :aria-label="`Page ${pageNum}`"
                    :aria-current="pageValue === pageNum ? 'page' : null"
                >
        
                    <span class="sr-only">Go to page</span>
                    {{ pageNum }}
                </button>
            </li>
            <template v-if="showLastVisiblePage">
                <li :class="listItemClasses">
                    ...
                </li>
                <li :class="listItemClasses">
                    <button
                        @click="goToPage(totalPages)"
                        :class="pageNumberBtnClasses"
                    >
                        {{ totalPages }}
                    </button>
                </li>
            </template>
        </ul>
        <button
            :class="nextBtnClasses"
            @click="goToNextPage"
            :disabled="nextPageButtonDisabled"
        >
            <slot name="next-page-btn" />
        </button>
    </nav>
</template>

<script>
    function paginate(currentPage, totalPages, maxPages) {
        const HALF_DIVIDER = 2;
        let startPage = 1;
        let endPage = 1;

        if (totalPages <= maxPages) {
            // total pages less than max so show all pages
            startPage = 1;
            endPage = totalPages;

            // create an array of pages to repeat over
            return Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
        }

        // total pages more than max so calculate start and end pages
        const maxPagesBeforeCurrentPage = Math.floor(maxPages / HALF_DIVIDER);
        const maxPagesAfterCurrentPage = Math.ceil(maxPages / HALF_DIVIDER) - 1;

        if (currentPage <= maxPagesBeforeCurrentPage) {
            // current page near the start
            if (maxPages === 2) {
                startPage = currentPage;
            } else {
                startPage = 1;
            }
            endPage = maxPages;
        } else if (currentPage + maxPagesAfterCurrentPage >= totalPages) {
            // current page near the end
            startPage = totalPages - maxPages + 1;
            endPage = totalPages;
        } else {
            // current page somewhere in the middle
            if (maxPages === 2) {
                startPage = currentPage;
                endPage = currentPage + 1;
            } else {
                startPage = currentPage - maxPagesBeforeCurrentPage;
                endPage = currentPage + maxPagesAfterCurrentPage;
            }
        }

        // create an array of pages to repeat over
        return Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
    }

    function determineCurrentPageValue(currentPage, totalPages) {
        if (currentPage < 1) {
            return 1;
        } else if (currentPage > totalPages) {
            return totalPages;
        }

        return currentPage;
    }


    export default {
        name: 'C2Pagination',
        props: {
            activePageNumberBtnClasses: {
                type: String,
                default: null,
            },
            currentPage: {
                type: Number,
                default: 1
            },
            maxPagesVisible: {
                type: Number,
                default: 7
            },
            totalPages: {
                type: Number,
                required: true
            },
            previousBtnClasses: {
                type: String,
                default: null
            },
            listClasses: {
                type: String,
                default: null
            },
            listItemClasses: {
                type: String,
                default: null
            },
            pageNumberBtnClasses: {
                type: String,
                default: null
            },
            nextBtnClasses: {
                type: String,
                default: null
            }
        },
        data() {
            return {
                pageCount: 1,
                pageValue: 1,
                showLastVisiblePage: false
            }
        },
        computed: {
            nextPageButtonDisabled() {
                return this.pageValue >= this.pageCount;
            },
            previousPageButtonDisabled() {
                return this.pageValue <= 1;
            },
            visiblePages() {
                return paginate(this.pageValue, this.pageCount, this.maxPagesVisible);
            },
        },
        watch: {
            currentPage() {
                this.pageValue = determineCurrentPageValue(this.currentPage, this.totalPages);
            },
            pageValue() {
                this.checkLastPage();
            },
            totalPages() {
                // if the total pages change, then we're resetting everything
                this.pageValue = 1;
                this.pageCount = this.totalPages;
            }
        },
        mounted() {
            this.pageValue = determineCurrentPageValue(this.currentPage, this.totalPages);
            this.pageCount = this.totalPages;
            this.checkLastPage();
        },
        methods: {
            goToPage(pageNum) {
                this.pageValue = parseInt(pageNum, 10);
                this.$emit('change', this.pageValue);
            },
            goToNextPage() {
                if (this.pageValue <= this.pageCount) {
                    this.pageValue++;
                    this.$emit('change', this.pageValue);
                }
            },
            goToPreviousPage() {
                if (this.pageValue >= 1) {
                    this.pageValue--;
                    this.$emit('change', this.pageValue);
                }
            },
            checkLastPage() {
                if (this.visiblePages.includes(this.totalPages)) {
                    this.showLastVisiblePage = false;
                } else {
                    this.showLastVisiblePage = true;
                }
            }
        }
    }
</script>

<style lang="scss">
</style>