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

<style>
    .console-content {
        height: calc(100vh - 378px);
        margin: 0;
    }

    .nui-height{
        height: calc(100vh - 230px);
    }

    .console-input {
        max-width: 24rem !important;
        width: 100% !important;
        margin-bottom: 1em;
    }

    #cmdHistoryDiv{
        display: inline-block;
    }

    @media (max-width: 1200px) {
        #cmdHistoryDiv{
            text-align: center!important;
        }
    }

    /* Custom Scrollbar colors for dark console */
    .console-content::-webkit-scrollbar-track {
        background-color: #1E252D;
        border-right: 1px solid #1E252D;
        border-left: 1px solid #1E252D;
    }

    .console-content::-webkit-scrollbar-thumb {
        background-color: #565C62;
    }

    .console-content::-webkit-scrollbar-corner {
        background: #1E252D;
    }

    .bg-dark {
        background-color: #252E38 !important;
    }

    .command-history {
        line-height: 2rem;
        display: inline-block;
    }

    .command-history > button {
        background-color: transparent !important;
        color: #768192 !important;
        border: 1px solid #768192;
    }

    .command-history > button:hover {
        background-color: transparent !important;
        color: rgb(183, 189, 199)!important;
        border: 1px solid rgb(183, 189, 199);
    }
</style>


<div class="text-center">
    <h3><%= serverName %> Console</h3>
</div>
<div class="card bg-dark">
    <div class="card-body p-3" style="position: relative">
        <pre id="console" class="thin-scroll console-content text-white <%= (isWebInterface ? '' : 'nui-height') %>"></pre>
        <div id="autoScrollDiv">
            <a id="autoScrollBtn" class="d-none" href="#"><span></span><span></span><span></span></a>
        </div>
    </div>
    <div class="card-footer bg-dark">
        <div class="row">
            <div class="col-xl-6 col-lg-12">
                <form class="form-inline container-fluid text-center" id="frmConsole">
                    <div class="mx-auto">
                        <div class="form-group">
                            <input type="text" class="form-control console-input form-control-sm" id="cmdInput"
                                   placeholder="Press enter to send. Up/Down arrows to navigate commands."
                                   autocomplete="off" autocorrect="off" autocapitalize="off"
                                   spellcheck="false" <%= disableCommand %>>
                        </div>
                        <a href="fxserver/downloadLog" target="_blank" 
                            class="btn btn-outline-light btn-sm mb-2 <%= (isWebInterface ? '' : 'disabled') %>">
                            Download Log
                        </a>
                        <button type="button" id="clearConsole" class="btn btn-outline-light btn-sm mb-2">
                            Clear Console
                        </button>
                        <button type="button" id="announcementBtn" class="btn btn-outline-warning btn-sm mb-2" <%= disableAnnouncement %>>
                            Announcement
                        </button>
                        <button type="button" id="ctrl-restart" class="btn btn-outline-danger btn-sm mb-2" 
                            onclick="controlAction('restart')" <%= disableRestart %>>
                                RESTART
                        </button>
                    </div>
                </form>
            </div>
            <div class="col-xl-6 col-lg-12" id="cmdHistoryDiv">
                <span class="text-light font-weight-bold">History:</span> <small class="text-muted">(click to copy)</small><br>
                <div class="command-history" id="cmdHistory"></div>
            </div>
        </div>

    </div>
</div>


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


<script src="js/ansi_up.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.min.js"></script>
<script>
    //============================================== Controls (start/restart/stop)
    async function controlAction(action) {
        const confirmOptions = {content: `Are you sure you would like to <b>${action}</b> the server?`};
        if(action !== 'start' && !await txAdminConfirm(confirmOptions)){
            return;
        }
        const notify = $.notify({ message: '<p class="text-center">Executing Command...</p>' }, {});
        txAdminAPI({
            url: actionURL = '/fxserver/controls/' + action,
            type: "GET",
            dataType: "json",
            timeout: REQ_TIMEOUT_LONG,
            success: function (data) {
                updateMarkdownNotification(data, notify);
            },
            error: function (xmlhttprequest, textstatus, message) {
                notify.update('progress', 0);
                notify.update('type', 'danger');
                notify.update('message', message);
            }
        });
    }

    //============================================== Live Console stuff
    (function () {
        //Preparing variables
        const BUFFER_TRIM_SIZE = 128 * 1024; // 128kb
        const commandHistoryLimit = 12;
        const defaultSocketOpts = {
            transports: ['polling'],
            upgrade: false,
            query: {
                room: 'liveconsole'
            }
        }
        let socket;
        if (isWebInterface) {
            socket = io({...defaultSocketOpts, path: '/socket.io'});
        }else{
            socket = io('monitor', {...defaultSocketOpts, path: '/WebPipe/socket.io'});
        }
        
        const ansi_up = new AnsiUp;
        ansi_up.escape_for_html = false;
        const input = document.getElementById("cmdInput");
        const consoleElement = document.getElementById("console");
        const consoleForm = document.getElementById("frmConsole");
        const historyDiv = document.getElementById('cmdHistoryDiv');
        const historyElement = document.getElementById('cmdHistory');
        const autoScrollBtn = document.getElementById("autoScrollBtn");
        const announcementBtn = document.getElementById("announcementBtn");
        let commandHistory = [];
        let commandCache = [];
        let autoScroll = true;
    

        //Helper Functions
        const stringToDOMId = (str) => `${str.replace(/\s?\s+/g, '-').slice(0, 32)}${str.length > 32 ? '_trim' : ''}`.trim();

        const addCommandHistoryEntry = (command) => {
            const btnText = `${command.slice(0, 15)}${command.length > 15 ? '...' : ''}`;
            const node = document.createElement('button');
            node.appendChild(document.createTextNode(btnText));
            node.setAttribute('id', stringToDOMId(command));
            node.setAttribute('class', 'btn btn-outline-light btn-sm m-1');
            node.onclick = (e) => {
                console.log('onclick')
                input.value = command;
                input.focus();
            };
            historyElement.appendChild(node);
        }

        const scrollBottom = () => {
            if (autoScroll) consoleElement.scrollTop = consoleElement.scrollHeight;
        }

        const autoscrollToggle = (status) => {
            autoScroll = status
            if(autoScroll){
                autoScrollBtn.classList.add('d-none');
            }else{
                autoScrollBtn.classList.remove('d-none');
            }
            scrollBottom();
        }

        //Load command history from local storage
        if(typeof window.localStorage.liveConsoleCommandHistory !== 'undefined'){
            try {
                const fromStorage = JSON.parse(window.localStorage.liveConsoleCommandHistory);
                commandHistory = fromStorage.slice(0 - commandHistoryLimit);
                commandHistory.forEach(addCommandHistoryEntry);
            } catch (error) {
                console.error('Failed to process window.localStorage.liveConsoleCommandHistory');
            }
        }

        
        //Events
        socket.on('error', (error) => {
            console.dir(error)
        });
        socket.on('connect', () => {
            console.log("Socket.IO Connected.");
        });
        socket.on('disconnect', () => {
            console.log("Socket.IO Disonnected.");
        });
        socket.on('goDashboard', (error) => {
            window.location = '/';
        });
        socket.on('consoleData', function (msg) {
            const cleanMsg = xss(msg)
                .replace(/<br>/g, '\n')
                .replace(/{txMarker-(\w+)}/g, '<mark class="consoleMark-$1">')
                .replace(/{\/txMarker}/g, '</mark>');

            let _consoleData = consoleElement.innerHTML + ansi_up.ansi_to_html(cleanMsg);
            _consoleData = (_consoleData.length > BUFFER_TRIM_SIZE)
                ? _consoleData.slice(-0.5 * BUFFER_TRIM_SIZE) // grab the last half
                : _consoleData; // no need to trim
            consoleElement.innerHTML = _consoleData.substr(_consoleData.indexOf("\n"));

            scrollBottom();
        });

        consoleElement.addEventListener('scroll',function(){
                const scrollTop = consoleElement.scrollTop;
                const scrollHeight = consoleElement.scrollHeight;
                const offsetHeight = consoleElement.offsetHeight;
                const contentHeight = scrollHeight - offsetHeight;
                if (scrollTop < contentHeight) {
                    autoscrollToggle(false);
                } else if(scrollTop === contentHeight){
                    autoscrollToggle(true);
                }
            }
        )


        //Form
        consoleForm.addEventListener("submit", function (e) {
            e.preventDefault();
            const command = input.value.trim();
            input.value = '';
            if(!command.length) return;

            commandCache.unshift(command);
            socket.emit('consoleCommand', command);

            autoscrollToggle(true);

            if(!commandHistory.includes(command)){
                addCommandHistoryEntry(command);
                commandHistory.push(command); //DEBUG valueToPush?
                // truncation
                if (commandHistory.length >= commandHistoryLimit) {
                    const search = commandHistory.find((_, index) => index === (commandHistory.length - commandHistoryLimit));
                    const element = document.getElementById(stringToDOMId(search));
                    element.remove();
                    commandHistory.shift();
                }
                window.localStorage.liveConsoleCommandHistory = JSON.stringify(commandHistory);
            }
        });


        //Up / Down history
        let currentIndex;
        input.addEventListener("keydown", function (event) {
            let changed = false;

            if (event.key === "ArrowUp") {
                changed = true;
                if (typeof currentIndex === 'undefined' && commandCache.length > 0) {
                    currentIndex = 0;
                } else if ((currentIndex + 1) < commandCache.length) {
                    currentIndex += 1;
                }

            } else if (event.key === "ArrowDown") {
                changed = true;
                if (currentIndex > 0) {
                    currentIndex -= 1;
                } else if (currentIndex === 0) {
                    currentIndex = undefined;
                }
            }

            if (changed) input.value = commandCache[currentIndex] || "";
        });

        //Buttons
        announcementBtn.addEventListener("click", async (event) => {
            const message = await txAdminPrompt({
                modalColor: 'orange',
                confirmBtnClass: 'btn-warning',
                title: 'Announcement',
                description: 'Type the message to be broadcasted to all players.', 
                placeholder: 'the server will restart in xxx minutes...'
            });

            if(message == false) return;
            if(message.length <= 6){
                $.notify({ message: 'This message is too short!'}, {type: 'danger'});
                return;
            }

            const notify = $.notify({ message: 'Executing Command...' }, {});
            txAdminAPI({
                type: "POST",
                url: '/fxserver/commands',
                data: {
                    action: 'admin_broadcast',
                    parameter: message
                },
                success: function (data) {
                    notify.update('progress', 0);
                    notify.update('type', data.type);
                    notify.update('message', data.message);
                },
                error: function (xmlhttprequest, textstatus, message) {
                    notify.update('progress', 0);
                    notify.update('type', 'danger');
                    notify.update('message', message);
                }
            });
        });

        autoScrollBtn.addEventListener("click", (event) => {
            event.preventDefault();
            autoscrollToggle(true);
        });

        document.getElementById("clearConsole").addEventListener("click", function () {
            consoleElement.innerHTML = "Console cleared.<br />\n";
        });
    })();
</script>
