import { fireEvent } from '@nimius/event-utility';

/**
 * @typedef {object} Pagination~options
 * @param {string} next
 * @param {string} prev
 * @param {string} page
 * @param {string} total
 */

export class Pagination {

    /**
     * @param {HTMLElement} wrapper
     * @param {Pagination~options} options
     */
    constructor(wrapper, options = {}) {

        /** @private {Pagination~options} */
        this.options = this.prepareOptions(options);

        /** @private {HTMLElement} */
        this.wrapper = wrapper;

        /** @private {number} */
        this.page = this.readCurrentPageFromDom() || 1;

        /** @private {object<string, Function[]>} */
        this.listeners = {};

        this.initializeButtonListeners();
        this.setInitialTotalPageCountFromDom();
    }

    /**
     * @param {int} totalPageCount
     * @public
     */
    setTotalPageCount(totalPageCount) {
        this.totalPageCount = totalPageCount;
    }

    /** @private */
    setInitialTotalPageCountFromDom() {
        if (this.wrapper.hasAttribute(this.options.total)) {
            this.setTotalPageCount(
                parseInt(this.wrapper.getAttribute(this.options.total), 10)
            );
        } else {
            const buttons = this.wrapper.querySelectorAll(`[${this.options.page}]`);
            const lastButton = buttons[buttons.length - 1];
            this.setTotalPageCount(
                parseInt(lastButton.getAttribute(this.options.page), 10)
            );
        }
    }

    /**
     * @param {int} page
     * @param {boolean} silent
     * @public
     */
    setPage(page, silent = false) {
        page = parseInt(page, 10);
        if (page <= 0 || page > this.totalPageCount) {
            return;
        }

        const emit = !silent && page !== this.page;

        this.page = page;
        if (emit) {
            fireEvent(this.wrapper, 'toubiz-pagination.page-select', {
                page: this.page,
            });
        }
    }

    /** @private */
    initializeButtonListeners() {
        for (const next of this.wrapper.querySelectorAll(`[${this.options.next}]`)) {
            next.addEventListener('click', event => {
                event.preventDefault();
                this.setPage(this.page + 1);
            });
        }

        for (const prev of this.wrapper.querySelectorAll(`[${this.options.prev}]`)) {
            prev.addEventListener('click', event => {
                event.preventDefault();
                this.setPage(this.page - 1);
            });
        }

        for (const element of this.wrapper.querySelectorAll(`[${this.options.page}]`)) {
            element.addEventListener('click', event => {
                event.preventDefault();
                const page = parseInt(element.getAttribute(this.options.page), 10);
                this.setPage(page);
            });
        }
    }

    /**
     * @returns {?int}
     * @private
     */
    readCurrentPageFromDom() {
        const element = this.wrapper.querySelector(`[${this.options.page}][aria-current]`);
        if (element) {
            return parseInt(element.getAttribute(this.options.page), 10);
        }
        return null;
    }

    /**
     * @param {Pagination~options} options
     * @returns {Pagination~options}
     * @private
     */
    prepareOptions(options) {
        options.next = options.next || 'data-toubiz-pagination-next';
        options.prev = options.prev || 'data-toubiz-pagination-prev';
        options.page = options.page || 'data-toubiz-pagination-page';
        options.total = options.total || 'data-toubiz-pagination-total';
        return options;
    }

}
