<%- await include('parts/header.ejs', locals) %>

<style>
    .header-elements {
        margin-top: auto;
        margin-bottom: auto;
    }
    .name-truncate {
        max-width: 8rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .discord-avatar {
        width: 1.25rem;
        height: 1.25rem;
        vertical-align: text-bottom;
    }
    .discord-tag {
        margin-left: 2px;
    }
    .action-buttons {
        text-decoration: none;
        font-size: 1.25em;
        margin-left: 4px;
    }
    .action-buttons:hover {
        text-decoration: none;
    }
    .action-buttons[disabled] {
        cursor: not-allowed;
        /* pointer-events: none; */
    }
    .action-buttons:hover:not([disabled]) > i {
        font-weight: 600;
    }
</style>

<% if (currentWhitelistMode !== 'approvedLicense') { %>
    <div class="row justify-content-md-center">
        <div class="col-md-6">
            <div class="alert alert-warning text-center" role="alert">
                <strong>Warning: The server is not in the "Approved License" allowlist mode.</strong> <br>
                This means that any changes made in this page will not reflect in the ability of players to connect to the server while the allowlist is in another mode or disabled. <br>
                This can be changed in the page <a href="#" onclick="navigateParentTo('/settings#allowlist')">Settings > Allowlist</a>.
            </div>
        </div>
    </div>
<% } %>

<div class="row justify-content-md-center">
    <!-- Requests card -->
    <div class="col-md-6 mw-col8">
        <div class="card card-accent-success">
            <div class="card-header" style="display: flex; justify-content: space-between;">
                <div>
                    <span style="font-size: large">Allowlist Requests: <span id="reqs-counter"></span></span> <br>
                    <small>Players that tried to join the server but were not allowlisted.</small>
                </div>
                <div class="header-elements">
                    <div class="form-group mb-0">
                        <div class="input-group input-group-sm">
                            <input class="form-control" id="reqs-searchInput" type="text"
                                placeholder="player name, R1234">
                            <span class="input-group-append">
                                <button class="btn btn-sm btn-secondary" type="button" id="reqs-searchButton">
                                    Search
                                </button>
                            </span>
                        </div>
                    </div>
                </div>
            </div>
            <div class="card-body">
                <div id="reqs-spinner" style="min-height: 125px;">
                    <div class="txSpinner">Loading...</div>
                </div>
                <div class="text-center">
                    <h3 class="mx-auto pt-3 text-muted d-none" id="reqs-message">no players here yet</h3>
                </div>
                <div class="table-responsive text-center d-nonex" id="reqs-content">
                    <table class="table table-responsive-sm table-borderless table-striped table-sm text-left">
                        <thead>
                            <tr class="text-left">
                                <th>ID</th>
                                <th>Name</th>
                                <th>Discord</th>
                                <th>Join Time</th>
                                <th class="text-right">Actions</th>
                            </tr>
                        </thead>
                        <tbody id="reqs-tableBody"></tbody>
                    </table>
                </div>
            </div>

            <div class="card-footer d-flex" style="flex-direction: row; justify-content: space-between;">
                <button class="btn btn-sm btn-outline-danger" type="button" id="reqs-denyAllBtton" onclick="denyAllRequests()">
                    <i class="icon-close"></i> Deny All
                </button>
                <ul class="pagination justify-content-center mb-0">
                    <li class="page-item disabled" id="reqs-paginator-prev">
                        <a class="page-link" href="#" onclick="event.preventDefault(); reqsPrevPage()">Previous</a>
                    </li>
                    <li class="page-item disabled" id="reqs-paginator-mid">
                        <a class="page-link" href="#">?</a>
                    </li>
                    <li class="page-item disabled" id="reqs-paginator-next">
                        <a class="page-link" href="#" onclick="event.preventDefault(); reqsNextPage()">Next</a>
                    </li>
                </ul>
            </div>
        </div>
    </div>

    <!-- Approved card -->
    <div class="col-md-6 mw-col8">
        <div class="card card-accent-success">
            <div class="card-header" style="display: flex; justify-content: space-between;">
                <div>
                    <span style="font-size: large">Approved Allowlists Pending Join: <span id="approved-counter"></span></span> <br>
                    <small>Players that are already approved, but haven't joined the server yet.</small>
                </div>
                <div class="header-elements">
                    <button class="btn btn-sm btn-success" type="button" onclick="addApproval()">
                        <i class="icon-plus"></i> Add Approval
                    </button>
                </div>
            </div>
            <div class="card-body">
                <div id="approved-spinner" style="min-height: 125px;">
                    <div class="txSpinner">Loading...</div>
                </div>
                <div class="text-center">
                    <h3 class="mx-auto pt-3 text-muted d-none" id="approved-message">no players here yet</h3>
                </div>
                <div class="table-responsive text-center d-nonex" id="approved-content">
                    <table class="table table-responsive-sm table-borderless table-striped table-sm text-left">
                        <thead>
                            <tr class="text-left">
                                <!-- <th>Identifier</th> -->
                                <th>Player</th>
                                <th>Approved By</th>
                                <th>Approval Date</th>
                                <th class="text-right">Actions</th>
                            </tr>
                        </thead>
                        <tbody id="approved-tableBody"></tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>



<!-- Template for Whitelists Requests entry lines -->
<template id="reqs-entryTemplate">
    <td></td>
    <td class="name-truncate"></td>
    <td class="name-truncate">
        <div class="c-avatar discord-avatar">
            <img class="c-avatar-img" src="">
        </div>
        <span class="discord-tag"></span>
    </td>
    <td></td>
    <td class="tableActions">
        <a href="#" class="action-buttons text-success" title="Approve">
            <i class="icon-check"></i>
        </a>
        <a href="#" class="action-buttons text-danger" title="Deny">
            <i class="icon-close"></i>
        </a>
    </td>
</template>

<!-- Template for Approved Whitelists entry lines -->
<template id="approved-entryTemplate">
    <td class="name-truncate">
        <div class="c-avatar discord-avatar">
            <img class="c-avatar-img" src="">
        </div>
        <span class="discord-tag"></span>
    </td>
    <td></td>
    <td></td>
    <td class="tableActions">
        <a href="#" class="action-buttons text-danger" title="Deny">
            <i class="icon-close"></i>
        </a>
    </td>
</template>


<%- await include('parts/footer.ejs', locals) %>


<script>
    const hasWhitelistPermission = ('<%= hasWhitelistPermission %>' === 'true');
    const disableActionButton = (e) => {
        e.title = 'You do not have this permission.';
        e.setAttribute('disabled', '');
        e.classList.remove('text-success', 'text-danger');
        e.classList.add('text-muted');
        e.addEventListener('click', (e) => {
            e.preventDefault();
        });
    }

    /**
     * WHITELIST REQUESTS
     */
    const reqElements = {
        spinner: document.getElementById('reqs-spinner'),
        message: document.getElementById('reqs-message'),
        content: document.getElementById('reqs-content'),
        counter: document.getElementById('reqs-counter'),
        tableBody: document.getElementById('reqs-tableBody'),
        entryTemplate: document.getElementById('reqs-entryTemplate'),
        searchInput: document.getElementById('reqs-searchInput'),
        searchButton: document.getElementById('reqs-searchButton'),
        denyAllBtton: document.getElementById('reqs-denyAllBtton'),
    };
    const paginator = {
        prev: document.getElementById('reqs-paginator-prev'),
        mid: document.getElementById('reqs-paginator-mid'),
        next: document.getElementById('reqs-paginator-next'),
    }
    let currentPage = 1;
    let activeSearchString = '';
    let newestRequest = 0;

    //If no perms, edit template
    if(!hasWhitelistPermission){
        reqElements.entryTemplate.content.querySelectorAll('.action-buttons').forEach(disableActionButton);
    }

    reqElements.searchButton.addEventListener('click', (e) => {
        if(reqElements.searchButton.innerText === 'Search'){
            performSearch();
        }else{
            clearSearch();
        }
    });
    reqElements.searchInput.addEventListener('keyup', (e) => {
        if(e.keyCode !== 13){
            if(reqElements.searchButton.innerText !== 'Search'){
                reqElements.searchButton.innerText = 'Search';
            }
        }else{
            if(reqElements.searchInput.value.length){
                performSearch();
            }else{
                clearSearch();
            }
        }
    });

    //Clear search
    function clearSearch(){
        reqElements.searchInput.value = '';
        reqElements.spinner.classList.remove('d-none');
        reqElements.content.classList.add('d-none');
        reqElements.message.classList.add('d-none');
        reqElements.searchButton.innerText = 'Search';
        activeSearchString = '';
        queryRequests();
    }

    //Perform search
    function performSearch(){
        activeSearchString = reqElements.searchInput.value.trim();
        if(!activeSearchString.length) return clearSearch();
        reqElements.spinner.classList.remove('d-none');
        reqElements.content.classList.add('d-none');
        reqElements.message.classList.add('d-none');
        reqElements.searchButton.innerText = 'Clear';
        queryRequests();
    }

    //Performs auto-search
    const urlHash = decodeURI(location.hash.substr(1).trim());
    if(urlHash.length){
        reqElements.searchInput.value = urlHash;
    }
    performSearch();

    const fillRequestsTableRows = (reqsArray) => {
        reqElements.tableBody.innerHTML = '';

        for (const req of reqsArray) {
            const newNode = document.createElement("tr");
            newNode.innerHTML = reqElements.entryTemplate.innerHTML;
            newNode.querySelector('td:nth-child(1)').textContent = req.id;
            newNode.querySelector('td:nth-child(2)').textContent = req.playerDisplayName;
            newNode.querySelector('td:nth-child(2)').title = `${req.playerDisplayName}\nlicense:${req.license}`;
            newNode.querySelector('td:nth-child(3)').title = req.discordTag;
            newNode.querySelector('td:nth-child(3) div img').src = req.discordAvatar
                ? req.discordAvatar
                : 'img/default_avatar.png';
            newNode.querySelector('td:nth-child(3) span').textContent = req.discordTag
                ? req.discordTag
                : 'not available';

            const tsLastAttempt = new Date(req.tsLastAttempt * 1000)
            newNode.querySelector('td:nth-child(4)').title = tsLastAttempt.toLocaleString(
                navigator.language,
                { dateStyle: 'long', timeStyle: 'long' }
            );
            newNode.querySelector('td:nth-child(4)').textContent = tsLastAttempt.toLocaleString(
                navigator.language,
                { dateStyle: 'short', timeStyle: 'short' }
            );

            newNode.querySelector('td:nth-child(5) a:nth-child(1)').addEventListener('click', (e) => {
                e.preventDefault();
                if(!hasWhitelistPermission) return;
                approveDenyRequest(req.id, 'approve');
            });
            newNode.querySelector('td:nth-child(5) a:nth-child(2)').addEventListener('click', (e) => {
                e.preventDefault();
                if(!hasWhitelistPermission) return;
                approveDenyRequest(req.id, 'deny');
            });

            reqElements.tableBody.appendChild(newNode);
        }
    }

    function setPaginator(currPage, totalPages){
        currentPage = currPage;
        paginator.mid.querySelector('a').textContent = currPage;
        if(currPage > 1){
            paginator.prev.classList.remove('disabled');
        }else{
            paginator.prev.classList.add('disabled');
        }
        if(totalPages > currPage){
            paginator.next.classList.remove('disabled');
        }else{
            paginator.next.classList.add('disabled');
        }
    }

    function reqsPrevPage(){
        queryRequests(currentPage > 1 ? currentPage - 1 : 1);
    }
    function reqsNextPage(){
        queryRequests(currentPage + 1);
    }

    function queryRequests(page){
        location.hash = encodeURI(activeSearchString);
        const urlSearch = new URLSearchParams();
        if(activeSearchString) urlSearch.append('searchString', activeSearchString);
        if(page) urlSearch.append('page', page);

        txAdminAPI({
            type: "GET",
            url: `/whitelist/requests?${urlSearch.toString()}`,
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                reqElements.spinner.classList.add('d-none');
                reqElements.denyAllBtton.disabled = true;
                if(data.error){
                    reqElements.message.classList.remove('d-none', 'text-muted');
                    reqElements.message.classList.add('text-danger');
                    reqElements.message.textContent = `Error: ${data.error}`;
                }else if(!Array.isArray(data.requests)){
                    reqElements.message.classList.remove('d-none', 'text-muted');
                    reqElements.message.classList.add('text-danger');
                    reqElements.message.textContent = 'Error reading API response';
                }else if(!data.requests.length){
                    setPaginator(1, 1);
                    newestRequest = data.newest;
                    reqElements.counter.innerText = 0;
                    reqElements.content.classList.add('d-none');
                    reqElements.message.classList.remove('d-none');
                }else{
                    newestRequest = data.newest;
                    setPaginator(data.currPage, data.totalPages);
                    if(data.cntTotal === data.cntFiltered){
                        reqElements.counter.innerText = data.cntTotal;
                        reqElements.denyAllBtton.disabled = false;
                    }else{
                        reqElements.counter.innerText = `${data.cntFiltered} of ${data.cntTotal}`;
                    }
                    reqElements.message.classList.add('d-none');
                    reqElements.content.classList.remove('d-none');
                    fillRequestsTableRows(data.requests);
                }
            },
            error: function (xmlhttprequest, textstatus, message) {
                reqElements.spinner.classList.add('d-none');
                reqElements.message.classList.remove('d-none', 'text-muted');
                reqElements.message.classList.add('text-danger');
                reqElements.message.textContent = 'Error reading API response';
            }
        });
    }
    

    function approveDenyRequest(reqId, action){
        const notify = $.notify({ message: '<p class="text-center">Processing...</p>' }, {});

        txAdminAPI({
            type: 'POST',
            url: `/whitelist/requests/${action}`,
            data: {reqId},
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                notify.update('progress', 0);
                if (data.success === true) {
                    window.location.reload(true);
                    return true;
                } else {
                    notify.update('type', 'danger');
                    notify.update('message', data.error || 'unknown error');
                }
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }

    async function denyAllRequests(reqId, action){
        const confirmOptions = {
            title: 'Deny all allowlist requests?',
            content: `Players will still be able to try to join again, and will receive a new request ID.`,
        };
        if (!await txAdminConfirm(confirmOptions)) return;

        const notify = $.notify({ message: '<p class="text-center">Processing...</p>' }, {});

        txAdminAPI({
            type: 'POST',
            url: `/whitelist/requests/deny_all`,
            data: {newestVisible: newestRequest},
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                notify.update('progress', 0);
                if (data.success === true) {
                    window.location.reload(true);
                    return true;
                } else {
                    notify.update('type', 'danger');
                    notify.update('message', data.error || 'unknown error');
                }
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }


    
    
    /**
     * APPROVED WHITELISTS
     */
    const approvedElements = {
        spinner: document.getElementById('approved-spinner'),
        message: document.getElementById('approved-message'),
        content: document.getElementById('approved-content'),
        counter: document.getElementById('approved-counter'),
        tableBody: document.getElementById('approved-tableBody'),
        entryTemplate: document.getElementById('approved-entryTemplate'),
    };

    //If no perms, edit template
    if(!hasWhitelistPermission){
        approvedElements.entryTemplate.content.querySelectorAll('.action-buttons').forEach(disableActionButton);
    }

    const fillApprovedTableRows = (approvalsArray) => {
        for (const approval of approvalsArray) {
            const newNode = document.createElement("tr");
            newNode.innerHTML = approvedElements.entryTemplate.innerHTML;
            newNode.querySelector('td:nth-child(1) div img').src = approval.playerAvatar
                ? approval.playerAvatar
                : 'img/default_avatar.png';
            newNode.querySelector('td:nth-child(1) span').textContent = approval.playerName;
            newNode.querySelector('td:nth-child(1) span').title = `${approval.playerName}\n${approval.identifier}`;
            newNode.querySelector('td:nth-child(2)').textContent = approval.approvedBy;

            const tsApproved = new Date(approval.tsApproved * 1000)
            newNode.querySelector('td:nth-child(3)').title = tsApproved.toLocaleString(
                navigator.language,
                { dateStyle: 'long', timeStyle: 'long' }
            );
            newNode.querySelector('td:nth-child(3)').textContent = tsApproved.toLocaleString(
                navigator.language,
                { dateStyle: 'short', timeStyle: 'short' }
            );

            newNode.querySelector('td:nth-child(4) a:nth-child(1)').addEventListener('click', (e) => {
                e.preventDefault();
                if(!hasWhitelistPermission) return;
                removeApproval(approval.identifier)
            });

            approvedElements.tableBody.appendChild(newNode);
        }
    }

    txAdminAPI({
        type: "GET",
        url: '/whitelist/approvals',
        timeout: REQ_TIMEOUT_LONG,
        success: function (data) {
            approvedElements.spinner.classList.add('d-none');
            if(data.error){
                approvedElements.message.classList.remove('d-none', 'text-muted');
                approvedElements.message.classList.add('text-danger');
                approvedElements.message.textContent = `Error: ${data.error}`;
            }else if(!Array.isArray(data)){
                approvedElements.message.classList.remove('d-none', 'text-muted');
                approvedElements.message.classList.add('text-danger');
                approvedElements.message.textContent = 'Error reading API response';
            }else if(!data.length){
                approvedElements.counter.innerText = 0;
                approvedElements.content.classList.add('d-none');
                approvedElements.message.classList.remove('d-none');
            }else{
                approvedElements.counter.innerText = data.length;
                approvedElements.message.classList.add('d-none');
                approvedElements.content.classList.remove('d-none');
                fillApprovedTableRows(data);
            }
        },
        error: function (xmlhttprequest, textstatus, message) {
            approvedElements.spinner.classList.add('d-none');
            approvedElements.message.classList.remove('d-none', 'text-muted');
            approvedElements.message.classList.add('text-danger');
            approvedElements.message.textContent = 'Error reading API response';
        }
    });

    async function addApproval(){
        //TODO: when migrating to react, get this from the shared folder
        const acceptedIdTypes = ['discord', 'fivem', 'license', 'license2', 'live', 'steam', 'xbl'];
        let identifier = await txAdminPrompt({
            modalColor: 'green',
            confirmBtnClass: 'btn-green',
            title: 'Allowlist player',
            description: `Type in the Player Identifier you want to allowlist. <br>
                This can be any of the following: <code>${acceptedIdTypes.join(', ')}</code>`, 
            placeholder: 'discord:272800190639898628'
        });
        if(typeof identifier !== 'string') return;
        
        //Check input validity
        identifier = identifier.trim();
        if(!identifier.length || !acceptedIdTypes.includes(identifier.split(':', 1)[0])){
            return $.notify({ message: 'Error: the provided identifier does not seem to be valid.' }, { type: 'danger' });
        }

        const notify = $.notify({ message: '<p class="text-center">Processing...</p>' }, {});
        txAdminAPI({
            type: 'POST',
            url: '/whitelist/approvals/add',
            data: {identifier},
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                notify.update('progress', 0);
                if (data.success === true) {
                    // notify.update('type', 'success');
                    // notify.update('message', 'xxxxxxx.');
                    window.location.reload(true);
                    return true;
                } else {
                    notify.update('type', 'danger');
                    notify.update('message', data.error || 'unknown error');
                }
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }

    function removeApproval(identifier){
        const notify = $.notify({ message: '<p class="text-center">Processing...</p>' }, {});

        txAdminAPI({
            type: 'POST',
            url: '/whitelist/approvals/remove',
            data: {identifier},
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                notify.update('progress', 0);
                if (data.success === true) {
                    // notify.update('type', 'success');
                    // notify.update('message', 'xxxxxxx.');
                    window.location.reload(true);
                    return true;
                } else {
                    notify.update('type', 'danger');
                    notify.update('message', data.error || 'unknown error');
                }
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }

</script>
