import React, {Fragment, useState} from 'react';

const SPACE_A = 'SPACE_A';
const SPACE_B = 'SPACE_B';

/**
 * Helper method for creating a range of numbers
 * range(1, 5) => [1, 2, 3, 4, 5]
 */
const range = (from, to, step = 1) => {
    let i = from;
    const range = [];

    while (i <= to) {
        range.push(i);
        i += step;
    }

    return range;
}

export const Paginate = (props) => {
    const pageLimit = typeof props.pageLimit === 'number' ? props.pageLimit : 30;
    const totalRecords = typeof props.totalRecords === 'number' ? props.totalRecords : 0;
    const pageNeighbours = typeof props.pageNeighbours === 'number' ? Math.max(0, Math.min(props.pageNeighbours, 2)) : 0;
    const totalPages = Math.ceil(totalRecords / pageLimit);
    const [currentPage, setCurrentPage] = useState(typeof props.currentPage === 'number' ? props.currentPage : 1);
    let hasLeft = false;
    let hasRight = false;

    const gotoPage = (page) => {
        const currentPage = Math.max(0, Math.min(page, totalPages));
        props.onPageChanged(page)
        setCurrentPage(currentPage);
    }

    const handleClick = (page) => (evt) => {
        evt.preventDefault();
        document.getElementById('root').scrollIntoView({behavior: 'smooth'});
        if (currentPage !== page) gotoPage(page);
    }

    const handleMoveLeft = (evt) => {
        evt.preventDefault();
        gotoPage(currentPage - 1);
    }

    const handleMoveRight = (evt) => {
        evt.preventDefault();
        gotoPage(currentPage + 1);
    }

    const makePageLink = (page) => props.makeLink(page);

    /**
     * Let's say we have 10 pages and we set pageNeighbours to 2
     * Given that the current page is 6
     * The pagination control will look like the following:
     *
     * (1) < {4 5} [6] {7 8} > (10)
     *
     * (x) => terminal pages: first and last page(always visible)
     * [x] => represents current page
     * {...x} => represents page neighbours
     */
    const fetchPageNumbers = () => {
        /**
         * totalNumbers: the total page numbers to show on the control
         * totalBlocks: totalNumbers + 2 to cover for the left(<) and right(>) controls
         */
        const totalNumbers = (pageNeighbours * 2) + 3;
        const totalBlocks = totalNumbers + 2;

        if (totalPages > totalBlocks) {
            const startPage = Math.max(2, currentPage - pageNeighbours);
            const endPage = Math.min(totalPages - 1, currentPage + pageNeighbours);

            let pages = range(startPage, endPage);

            /**
             * hasLeftSpill: has hidden pages to the left
             * hasRightSpill: has hidden pages to the right
             * spillOffset: number of hidden pages either to the left or to the right
             */
            const hasLeftSpill = startPage > 2;
            const hasRightSpill = (totalPages - endPage) > 1;
            const spillOffset = totalNumbers - (pages.length + 1);

            // handle: (1) < {5 6} [7] {8 9} (10)
            if (hasLeftSpill && !hasRightSpill) {
                const extraPages = range(startPage - spillOffset, startPage - 1);
                hasLeft = true;
                pages = [1, SPACE_A, ...extraPages, ...pages];
                // handle: (1) {2 3} [4] {5 6} > (10)
            } else if (!hasLeftSpill && hasRightSpill) {
                const extraPages = range(endPage + 1, endPage + spillOffset);
                hasRight = true;
                pages = [1, ...pages, ...extraPages, SPACE_B, totalPages];
                // handle: (1) < {4 5} [6] {7 8} > (10)
            } else if (hasLeftSpill && hasRightSpill) {
                hasLeft = true;
                hasRight = true;
                pages = [1, SPACE_A, ...pages, SPACE_B, totalPages];
            }

            return pages;

        }

        return range(1, totalPages);
    }


    if (!totalRecords || totalPages === 1) return null;

    const pages = fetchPageNumbers();
    const blocks = pages.map((page, index) => {
        if (page === SPACE_A || page === SPACE_B) return (
            <span key={page} className='spacing'>…</span>
        );
        return (
            <li key={page} className='page-item '>
                <a className={`page-link ${currentPage === page ? 'active' : ''}`} href={makePageLink(page)} onClick={handleClick(page)}>{page}</a>
            </li>
        );
    })

    return (
        <Fragment>
            <ul className="pagination">
                { hasLeft ?
                    <li key='left' className="page-item left">
                        <a className="page-link" href={makePageLink(currentPage - 1)} onClick={handleMoveLeft}>
                            <span>Anterior</span>
                        </a>
                    </li>
                    :
                    <li key='left' className="page-item left"/>
                }
                <ul key='center' className='page-center'>
                    {blocks}
                </ul>
                {hasRight ?
                    <li key='right' className="page-item right">
                        <a className="page-link" href={makePageLink(currentPage + 1)} onClick={handleMoveRight}>
                            <span>Siguiente</span>
                        </a>
                    </li>
                    :
                    <li key='right' className="page-item right"/>
                }
            </ul>
        </Fragment>
    );

}

