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


<style>
    .pre-log-content {
        height: calc(100vh - 270px); /* -251px */
        margin-bottom: 0;
        font-size: 100%;
        /* word-break: break-all; */
    }

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

    .card {
        height: 100%;
        margin-bottom: 0 !important;
    }

    .e-src{
        color: var(--dark);
        font-weight: 900 !important;
        padding: .15rem;
        margin-left: .25rem;
        margin-right: .25rem;
    }
    .e-src-player{
        color: var(--primary);
        font-weight: 900 !important;
        cursor: pointer;
    }
    .e-src-player:hover{
        /* color: var(--warning); */
        color: var(--light);
        background-color: var(--dark);
    }

    .filter-controls-container {
        margin-top: 10px;
    }

    .filter-show-toggle {
        display: none;
    }

    @media only screen and (max-width: 1200px) {
        .card-containers {
            margin-bottom: 20px;
        }

        .filter-show-toggle {
            display: flex;
        }

        .section-title {
            display: flex;
            flex-basis: 0 ;
            justify-content: center;
            align-items: center;
        }
    }

    @media (min-width: 1250px) and (max-width: 1450px)  {
        .override-bootstrap {
            flex: 0 0 auto !important;
        }
    }


</style>


<div class="row">
    <div class="col-lg-3 col-md-12 card-containers" style="min-width: 235px;">
        <div class="card" >
            <div class="card-body text-center">
                <div id="cardstatus">
                    <h4>Mode: <span class="text-success" id="modeLabel">LIVE</span></h4>
                    <p>
                        <strong>From:</strong> <span id="histLogStart">--</span> <br>
                        <strong>To:</strong> <span id="histLogEnd">--</span> <br>
                    </p>
                    <button type="button" class="btn btn-outline-dark btn-sm mb-2" id="viewOlderBtn">
                        &lt; View Older
                    </button>
                    <button type="button" class="btn btn-outline-dark btn-sm mb-2" id="viewNewerBtn">
                        View Newer &gt;
                    </button>
                    <br>
                    <button type="button" id="clearConsole" class="btn btn-outline-dark btn-sm mb-2">
                        Clear Console
                    </button>
                    <!-- TODO: add modal -->
                    <button type="button" id="showLogsModalBtn" class="btn btn-outline-dark btn-sm mb-2 d-none">
                        Download Log
                    </button>
                </div>

                <hr class="border-primary">
                <div class='section-title'>
                    <button
                      style='margin-left: 10px;'
                      class='btn btn-outline-info filter-show-toggle rounded'
                      data-toggle='collapse'
                      href="#filter-control-container"
                      role='button'
                      aria-expanded='false'
                      aria-controls='collapseControls'>
                        Show Log Filters
                    </button>
                </div>
                <div class='filter-controls-container' id='filter-control-container'>
                    <h4>Logger Filters</h4>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Player Joins</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="PlayerJoin">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Player Leaves</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="playerDropped">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Chat Messages</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="ChatMessage">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Player Death</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="DeathNotice">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Menu Actions</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="MenuEvent">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Explosions</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="explosionEvent">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">Commands</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="CommandExecuted">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                    <div class="form-group row mb-1">
                        <label class="col-sm-8 col-form-label">System Events</label>
                        <div class="col-sm-4">
                            <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                                <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="System">
                                <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                            </label>
                        </div>
                    </div>
                </div>
                <!-- <div class="form-group row mb-1">
                    <label class="col-sm-8 col-form-label">Other Events</label>
                    <div class="col-sm-4">
                        <label class="c-switch c-switch-sm c-switch-label c-switch-pill c-switch-success fix-pill-form">
                            <input class="c-switch-input e-filter-sw" type="checkbox" checked data-e-type="other">
                            <span class="c-switch-slider" data-checked="On" data-unchecked="Off"></span>
                        </label>
                    </div>
                </div> -->

            </div>
        </div>
    </div>
    <div class="col-lg-9 col-md-12 card-containers override-bootstrap">
        <div class="card">
            <div class="card-body p-3" style="position: relative">
                <pre id="logContainer" class="thin-scroll pre-log-content <%= isWebInterface ? '' : 'nui-height' %>"></pre>
                <div id="autoScrollDiv">
                    <a id="autoScrollBtn" class="d-none" href="#"><span></span><span></span><span></span></a>
                </div>
            </div>
        </div>
    </div>
</div>


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


<script>
    (function () {
        //============================================== Moved from main.js
        function showPlayerByMutexNetid(mutexNetid) {
            const [mutex, netid] = mutexNetid.split(/[_#]/, 2);
            return window.parent.postMessage({ type: 'openPlayerModal', ref: { mutex, netid } });
        }

        const getSocket = (rooms) => {
            const socketOpts = {
                transports: ['polling'],
                upgrade: false,
                query: { rooms }
            };

            const socket = isWebInterface
                ? io({ ...socketOpts, path: '/socket.io' })
                : io('monitor', { ...socketOpts, path: '/WebPipe/socket.io' });

            socket.on('logout', () => {
                console.log('Received logout command from websocket.');
                window.parent.postMessage({ type: 'logoutNotice' });
            });

            return socket;
        }

        //============================================== Preparing variables
        const autoScrollBtn = document.getElementById("autoScrollBtn");
        const logContainer = document.getElementById("logContainer");
        const modeLabel = document.getElementById("modeLabel");
        const histLogStart = document.getElementById("histLogStart");
        const histLogEnd = document.getElementById("histLogEnd");
        const viewOlderBtn = document.getElementById("viewOlderBtn");
        const viewNewerBtn = document.getElementById("viewNewerBtn");
        const MAX_HISTORY_SIZE = 500;
        const frameTimeOptions = {weekday: 'long', hour: '2-digit', minute: '2-digit'};
        const eventTimeOptions = {hour: '2-digit', minute: '2-digit', second: '2-digit'};
        let logStartTs, logEndTs;
        let eventFilters = {};
        let autoScroll = true;
        const pageSocket = getSocket('serverlog');
        const logContainerSpinner = `<div style="height: 90%;" class="d-flex"><div style="margin: auto;">${SPINNER_HTML}</div></div>`;


        //============================================== Responsivity stuff
        const mql = window.matchMedia('(max-width: 992px)');
        const targetEl = document.getElementById('filter-control-container');
        if (mql.matches) {
          targetEl.classList.add('collapse');
        }

        mql.addEventListener("change", (e) => {
            if (e.matches && !targetEl.classList.contains('collapse')) {
              return targetEl.classList.add('collapse');
            }

            if (targetEl.classList.contains('collapse')) targetEl.classList.remove('collapse');
        })

        //============================================== Socket Stuff
        pageSocket.on('error', (error) => {
            console.log('Page Socket.IO', error)
        });
        pageSocket.on('connect', () => {
            console.log("Page Socket.IO Connected.");
            logContainer.innerHTML = '';
        });
        pageSocket.on('disconnect', (message) => {
            console.log("Page Socket.IO Disonnected:", message);
        });
        pageSocket.on('logData', processLog);

        //============================================== Mode selection
        function goLive() {
            logContainer.innerHTML = logContainerSpinner;
            modeLabel.classList.remove('text-warning');
            modeLabel.classList.add('text-success');
            modeLabel.textContent = 'LIVE';
            viewOlderBtn.disabled = false;
            viewNewerBtn.disabled = true;
            if (!pageSocket.connected) pageSocket.connect();
        }

        function goHistory(direction) {
            let ref;
            if(direction === 'older'){
                ref = logStartTs;
            }else if(direction === 'newer'){
                ref = logEndTs;
            }else{
                throw new Error(`unknown direction`);
            }
            pageSocket.disconnect();
            logContainer.innerHTML = logContainerSpinner;
            modeLabel.classList.add('text-warning');
            modeLabel.classList.remove('text-success');
            modeLabel.textContent = 'LOG';
            viewOlderBtn.disabled = false;
            viewNewerBtn.disabled = false;

            //Get log from API
            txAdminAPI({
                type: 'GET',
                url: `/serverLog/partial?dir=${direction}&ref=${ref}`,
                timeout: REQ_TIMEOUT_MEDIUM,
                success: function (data) {
                    logContainer.innerHTML = '';
                    if(!Array.isArray(data.log)){
                        logContainer.innerHTML = 'Failed to load log. Please refresh the page and try again.';
                        return;
                    }
                    //FIXME: reorganize this mess
                    if(data.boundry){
                        if(direction === 'older'){
                            if(!data.log.length){
                                logContainer.innerHTML = 'No more log entries to show.';
                            }else{
                                processLog(data.log);
                            }
                            viewOlderBtn.disabled = true;
                        }else{
                            goLive();
                        }
                        return;
                    }
                    processLog(data.log);

                    // TODO: da até pra depois do processLog() adicionar um <a> pra ir older ou newer
                },
                error: function (xmlhttprequest, textstatus, message) {
                    logContainer.innerHTML = 'Failed to load log. Please refresh the page and try again.';
                },
            });
        }

        // TODO: check if search string then do goLive() or goHistory()
        goLive();
        

        //============================================== Handling filters
        if(typeof window.localStorage.eventFilters !== 'undefined'){
            try {
                const fromStorage = JSON.parse(window.localStorage.eventFilters);
                console.log('Filters from storage:', fromStorage);
                if(typeof fromStorage === 'object' && fromStorage !== null) {
                    eventFilters = fromStorage;
                }
            } catch (error) {
                console.error('Failed to process window.localStorage.eventFilters');
            }
        }

        const allSwitches = document.querySelectorAll('.e-filter-sw');
        allSwitches.forEach((sw) => {
            sw.addEventListener('change', eventFiltersChanged);
            if(typeof eventFilters[sw.dataset.eType] === 'undefined'){
                eventFilters[sw.dataset.eType] = true;
            }
            sw.checked = eventFilters[sw.dataset.eType];
        });
        window.localStorage.eventFilters = JSON.stringify(eventFilters);

        const getShowTypes = () => Object.keys(eventFilters)
            .filter(fn => eventFilters[fn])
            .flatMap(fn => {
                if (fn === 'PlayerJoin') return ['playerJoining', 'playerJoinDenied'];
                if(fn === 'System') return ['LoggerStarted', 'DebugMessage'];
                return fn;
            });
        
        function eventFiltersChanged(caller){
            eventFilters[caller.target.dataset.eType] = caller.target.checked;
            window.localStorage.eventFilters = JSON.stringify(eventFilters);
            const showTypes = getShowTypes();
            console.log('showTypes:', showTypes);

            logContainer.childNodes.forEach(line => {
                if(showTypes.includes(line.dataset.eType)){
                    line.classList.remove('d-none');
                }else{
                    line.classList.add('d-none');
                }
            });
        }


        //============================================== AutoScroll Things
        const scrollBottom = () => {
            if (autoScroll) logContainer.scrollTop = logContainer.scrollHeight;
        }
        const autoscrollToggle = (status) => {
            autoScroll = status
            if(autoScroll){
                autoScrollBtn.classList.add('d-none');
            }else{
                autoScrollBtn.classList.remove('d-none');
            }
            scrollBottom();
        }
        logContainer.addEventListener('scroll',function(){
                const scrollTop = logContainer.scrollTop;
                const scrollHeight = logContainer.scrollHeight;
                const offsetHeight = logContainer.offsetHeight;
                const contentHeight = scrollHeight - offsetHeight;
                if (scrollTop < contentHeight) {
                    autoscrollToggle(false);
                } else if(scrollTop === contentHeight){
                    autoscrollToggle(true);
                }
            }
        )
        autoScrollBtn.addEventListener("click", (event) => {
            event.preventDefault();
            autoscrollToggle(true);
        });


        //============================================== Buttons
        document.getElementById("viewOlderBtn").addEventListener("click", function () {
            goHistory('older');
        });
        document.getElementById("viewNewerBtn").addEventListener("click", function () {
            goHistory('newer');
        });
        document.getElementById("clearConsole").addEventListener("click", function () {
            logContainer.innerHTML = "";
        });
        document.getElementById("showLogsModalBtn").addEventListener("click", function () {
            //TODO: add modal stuff
        });


        //============================================== Log processor
        function processLog(events) {
            console.log(`Events: ${events.length}`);
            const showTypes = getShowTypes();
            //For every new entry
            for (let i = 0; i < events.length; i++) {
                const event = events[i];
                logEndTs = event.ts;

                //Line
                const lineElement = document.createElement('div');
                lineElement.dataset.eTs = event.ts;
                lineElement.dataset.eType = event.type;
                if(!showTypes.includes(event.type)){
                    lineElement.classList.add('d-none');
                }

                //Time
                const localeTime = new Date(event.ts).toLocaleTimeString(window.navigator.language, eventTimeOptions);
                const timeNode = document.createElement('span');
                timeNode.textContent = `[${localeTime}]`;
                timeNode.classList.add('text-muted');
                lineElement.appendChild(timeNode);

                //Source
                const sourceNode = document.createElement('strong');
                sourceNode.classList.add('e-src');
                if(event.src.id){
                    const [mutex, netid] = event.src.id.split('#', 2);
                    sourceNode.classList.add('e-src-player');
                    sourceNode.addEventListener('click', ()=>{ showPlayerByMutexNetid(`${mutex}_${netid}`) });
                    sourceNode.textContent = `[${netid}] ${event.src.name}`;
                }else{
                    sourceNode.textContent = event.src.name;
                }
                lineElement.appendChild(sourceNode);

                //Message
                const msgNode = document.createTextNode(event.msg);
                lineElement.appendChild(msgNode);
                
                //Appending & capping log
                logContainer.appendChild(lineElement)
                if(logContainer.childNodes.length > MAX_HISTORY_SIZE){
                    logContainer.removeChild(logContainer.childNodes[0])
                }
            }

            //Process times
            logStartTs = parseInt(logContainer.childNodes[0].dataset.eTs);
            const logStartDate = new Date(logStartTs);
            const logEndDate = new Date(logEndTs);
            histLogStart.textContent = logStartDate.toLocaleString(window.navigator.language, frameTimeOptions);
            histLogEnd.textContent = logEndDate.toLocaleString(window.navigator.language, frameTimeOptions);

            //AutoScroll
            scrollBottom();
        }
    })();
</script>
