document.addEventListener('DOMContentLoaded', function () {
    function label(element, value) {
        if (element.hasAttribute('value')) {
            if (value !== undefined) {
                element.setAttribute('value', value)
            } else {
                return element.getAttribute('value')
            }
        } else {
            if (value !== undefined) {
                element.textContent = value
            } else {
                return element.textContent
            }
        }
    }

    function countdownDeleteButton(event) {
        const btn = event.target
        const countdown = btn.getAttribute('data-countdown')

        if (countdown !== '1') {
            event.preventDefault()
            btn.classList.add('__on-countdown')

            const hasCountdown = countdown !== null
            const newCountdown = hasCountdown ? countdown - 1 : 3

            if (!hasCountdown) {
                btn.setAttribute('data-label', label(btn))
            }

            label(btn, newCountdown)
            btn.setAttribute('data-countdown', newCountdown)
            setTimeout(countdownDeleteButton, 1000, event)
        } else {
            label(btn, btn.getAttribute('data-label'))
        }
    }

    document.querySelectorAll('.delete-btn').forEach(function (btn) {
        btn.addEventListener('click', countdownDeleteButton)
    })

    function dynamicTables() {
        const pageSize = 40

        const range = (x, y) =>
              x > y ? [] : [x, ...range(x + 1, y)];
        const visibleRows = page =>
              range(page * pageSize, (page + 1) * pageSize - 1)
        const tblRows = tbl =>
              [...tbl.tBodies[0].rows]
        const partial11 = (fn, arg1) =>
              function (arg2) {
                  fn(arg1, arg2)
              }
        const partial21 = (fn, arg1, arg2) =>
              function(arg3) {
                  fn(arg1, arg2, arg3)
              }

        function toggleVisibilities(tbl, ixsToShow) {
            tblRows(tbl).forEach(function (row, ix) {
                row.style.display = ixsToShow.includes(ix) ? 'table-row' : 'none';
            })
        }

        function setCurrPage(ctx, currPageIx) {
            const rows = tblRows(ctx.tbl).length
            const pages = Math.ceil(rows / pageSize)

            ctx.rowsLbls.forEach(function (elem) {
                elem.innerText = rows
            })

            ctx.pageLbls.forEach(function (elem) {
                elem.innerText = (currPageIx + 1) + ' / ' + pages
            })

            ctx.tbl.setAttribute('data-page', currPageIx)
        }

        function changePage(ctx, ix) {
            toggleVisibilities(ctx.tbl, visibleRows(ix))
            setCurrPage(ctx, ix)
        }

        function enablePagination(ctx, on) {
            [...ctx.nextBtns, ...ctx.prevBtns].forEach(function (btn) {
                btn.disabled = !on
            })
            ctx.pageLbls.forEach(function (elem) {
                elem.style.display = on ? 'inline' : 'none'
            })
        }

        function prevButton() {
            const btn = document.createElement('button')
            btn.classList.add('prev')
            btn.classList.add('pg-btn')
            btn.classList.add('btn')
            btn.classList.add('btn-light')
            return btn;
        }

        function nextButton() {
            const btn = document.createElement('button')
            btn.classList.add('next')
            btn.classList.add('pg-btn')
            btn.classList.add('btn')
            btn.classList.add('btn-light')
            return btn
        }

        function currPage() {
            const rowInfo = document.createElement('span')
            rowInfo.classList.add('row-info')
            const rows = document.createElement('span')
            rows.classList.add('rows')
            rows.innerText = '0'
            const page = document.createElement('span')
            page.classList.add('page')
            page.innerText = '1'

            rowInfo.insertAdjacentElement('afterbegin', rows)
            rowInfo.insertAdjacentElement('afterbegin', page)

            return rowInfo
        }

        function searchBox() {
            const input = document.createElement('input')
            input.classList.add('search')
            input.classList.add('form-control')
            input.type = 'search'
            input.placeholder = '🔍 ...'
            return input
        }

        function onSearch(ctx, evt) {
            const term = evt.target.value.toLocaleLowerCase()
            if (term.length === 0) {
                changePage(ctx, 0)
                enablePagination(ctx, true)
                return
            }

            enablePagination(ctx, false)

            const contents = tblRows(ctx.tbl).map(function (row) {
                return Array.from(row.cells).reduce(function (carr, cell) {
                    return carr + cell.textContent.toLocaleLowerCase()
                }, "")
            })

            const ixs = []
            contents.forEach(function (rowContent, ix) {
                if (rowContent.match(term)) {
                    ixs.push(ix)
                }
            })

            ctx.rowsLbls.forEach(function (elem) {
                elem.innerText = ixs.length
            })

            toggleVisibilities(ctx.tbl, ixs)
        }

        function onPrevClick(ctx) {
            const page = ctx.tbl.getAttribute('data-page') * 1
            if (page > 0) {
                changePage(ctx, page - 1)
            }
        }

        function onNextClick(ctx) {
            const page = ctx.tbl.getAttribute('data-page') * 1
            const lastRowNum = (page + 1) * pageSize
            if (lastRowNum < tblRows(ctx.tbl).length) {
                changePage(ctx, page + 1)
            }
        }

        function buildContext(tbl) {
            const currPage1 = currPage()
            const currPage2 = currPage()
            const ctx = {
                tbl: tbl,
                currPages: [currPage1, currPage2],
                pageLbls: [currPage1.children[0], currPage2.children[0]],
                rowsLbls: [currPage1.children[1], currPage2.children[1]],
                searchBox: searchBox(),
                prevBtns: [prevButton(), prevButton()],
                nextBtns: [nextButton(), nextButton()]
            }

            ctx.searchBox.addEventListener('input', partial11(onSearch, ctx))
            ctx.prevBtns.forEach(function (btn) {
                btn.addEventListener('click', partial11(onPrevClick, ctx))
            })
            ctx.nextBtns.forEach(function (btn) {
                btn.addEventListener('click', partial11(onNextClick, ctx))
            })

            return ctx
        }

        function addToolbar(tbl) {
            const ctx = buildContext(tbl)

            const toolbarTop = document.createElement('section')
            toolbarTop.classList.add('tbl-toolbar')
            toolbarTop.insertAdjacentElement('beforeend', ctx.currPages[0])
            toolbarTop.insertAdjacentElement('beforeend', ctx.searchBox)
            toolbarTop.insertAdjacentElement('beforeend', ctx.prevBtns[0])
            toolbarTop.insertAdjacentElement('beforeend', ctx.nextBtns[0])

            const toolbarBottom = document.createElement('section')
            toolbarBottom.classList.add('tbl-toolbar')
            toolbarBottom.insertAdjacentElement('beforeend', ctx.currPages[1])
            toolbarBottom.insertAdjacentElement('beforeend', ctx.prevBtns[1])
            toolbarBottom.insertAdjacentElement('beforeend', ctx.nextBtns[1])

            tbl.insertAdjacentElement('afterend', toolbarBottom)
            tbl.insertAdjacentElement('beforebegin', toolbarTop)

            return ctx
        }

        function flipSortDir(dir) {
            return (dir || 'asc') === 'asc' ? 'desc' : 'asc'
        }

        function clearSortAttributes(tbl) {
            [...tbl.tHead.rows[0].cells]
                .forEach(th => th.removeAttribute('data-sort'))
        }

        function onSort(ctx, ix, event) {
            const tbl = ctx.tbl

            const sortDir = event.target.getAttribute('data-sort') || 'asc'
            const sortMod = sortDir === 'asc' ? -1 : 1;

            const rows = tblRows(tbl)
            const newTbody = document.createElement('tbody')

            rows.sort((row1, row2) => {
                const val1 = row1.cells[ix].textContent
                const val2 = row2.cells[ix].textContent
                return sortMod * (val1 > val2 ? 1
                                  : val2 > val1 ? -1
                                  : 0);
            })

            rows.forEach(row => newTbody.appendChild(row))
            tbl.replaceChild(newTbody, tbl.tBodies[0])

            clearSortAttributes(tbl)
            event.target.setAttribute('data-sort', flipSortDir(sortDir))
            changePage(ctx, 0)
        }

        function enableSorting(ctx) {
            const ths = ctx.tbl.querySelectorAll('thead th')
            ths.forEach((th, ix) => {
                th.addEventListener('click', partial21(onSort, ctx, ix))
            })
        }

        document.querySelectorAll('table').forEach(function (tbl) {
            if (tbl.classList.contains('no-sort')) {
                return
            }
            const ctx = addToolbar(tbl)
            changePage(ctx, 0)
            enableSorting(ctx)
        })
    }

    dynamicTables()
})
