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

<style>
    /* Discord Live Event stuff */
    .event-time {
        background-color: rgba(0, 0, 0, 0.075);
        padding: 0px 6px;
        border-radius: 4px;
    }
    .event-footer {
        font-weight: 700;
        vertical-align: text-bottom;
    }
    .alert-title-icon {
        vertical-align: sub;
        fill: currentColor
    }

    .alert-success.event-live-glow {
        animation: alertGlow 1s infinite alternate;
    }
    @keyframes alertGlow {
        from {
            box-shadow: 0 0 8px 0px rgb(34, 128, 25);
        }
        to {
            box-shadow: 0 0 8px 4px rgb(34, 128, 25);
        }
    }

    /* Chart stuff */
    #d3-container {
        height: 340px;
        margin: auto;
        overflow: hidden;
    }
    #d3-container svg {
        height: 340px;
        width: 100%;
        margin: auto;
        overflow: hidden;
    }
    #x-axis path{
        stroke: none;
        fill: none;
    }
    #tickBucketsAxis path,
    #tickBucketsAxis line {
        stroke: none;
        fill: none;
    }
    .axis {
        color: dimgrey;
    }
    .axisTitle {
        color: dimgrey;
        font-size: 16px;
        font-weight: 500;
        margin: 2px calc(45px + 10px) 0px calc(27px + 10px);
        line-height: 1;
    }
    .axisTitle .tickTimeLabel{
        min-width: 2em;
        height: 18px;
        border: dimgrey 2px solid;
        background: rgb(35,23,27);
        /* background: linear-gradient(90deg, rgba(35,23,27,1) 10%, rgba(45,161,243,1) 35%, rgba(69,246,139,1) 65%, rgba(224,69,19,1) 90%); */
        background: linear-gradient(90deg, #482475 10%, #2f6c8e 35%, #2fb47c 65%, #bddf26 90%);
    }
    .axisTitle .clientsLabel{
        min-width: 2em;
        height: 18px;
        width: 6px;
        border: dimgrey 2px solid;
        background: rgb(204, 203, 203);
    }
    .axisTitle .labelText {
        
        margin-left: 0.2rem;
        margin-right: 1.2rem;
    }
    #chartThreadSelectBtn{
        padding: .1rem .4rem;
        font-size: .7rem;
    }
    .axisTitle .threadSelectDropdown{
        margin: 0px; position: absolute;
        inset: 0px auto auto 0px;
        transform: translate(0px, 26px);
        min-width: unset;
    }
    #d3-container-message {
        font-size: 2.25em;
        margin-top: 2em;
    }

    /* Other stuff */
    #status-card{
        font-size: 1.15rem;
        font-weight: 500;
        line-height: 2;
    }

    .dashboard-chart {
        width: 100% !important; 
        max-width: 890px !important;
    }
</style>

<!-- Title & outdated message: -->
<% if (isWebInterface) { %>
    <div class="text-center mb-4">
        <h2><%= serverName %> Dashboard</h2>
    </div>
<% } %>
<% if (txaOutdated) { %>
    <div class="row justify-content-md-center">
        <div class="col-md-6 text-center">
            <div class="alert alert-<%= txaOutdated.color %>" role="alert">
                <h5 style="margin-bottom: 0px;">
                    <svg class="alert-title-icon" width="22" height="22">
                        <use href="img/coreui_icons.svg#cil-cloud-download"></use>
                    </svg>
                    <% if (txaOutdated.semverDiff === 'patch') { %>
                        A patch (bug fix) update is available for txAdmin.
                    <% } else{ %> 
                        This version of txAdmin is outdated.
                    <% } %>
                </h5>
                <% if (txaOutdated.semverDiff === 'patch') { %>
                    If you are experiencing any kind of issue, please update now.
                <% } else{ %> 
                    Version <%= txaOutdated.latest %> has been released bringing new features, bug fixes and improvements. <br>
                    <div class="event-footer">
                        Please update now. Support Discord:
                        <a href="https://discord.gg/uAmsGa2" target="_blank" >
                            <img src="https://discordapp.com/api/guilds/577993482761928734/widget.png?style=shield"></img>
                        </a>
                    </div>
                <% } %>
                
            </div>
        </div>
    </div>
<% } %>

<% if (discordEvent) { %>
    <div class="row justify-content-md-center">
        <div class="col-md-6 text-center">
            <div class="alert <%= (discordEvent.isLive ? 'alert-success border-success' : 'alert-warning border-warning') %> event-live-glow" role="alert">
                <h5 style="margin-bottom: 0px;">
                    <svg class="alert-title-icon" width="22" height="22">
                        <use href="img/coreui_icons.svg#discord-event"></use>
                    </svg>
                    <%= (discordEvent.isLive ? 'The Discord Live Event started' : 'A Discord Live Event will start in') %>:
                    <span class="event-time" title="<%= (new Date(discordEvent.timestamp)).toString() %>"><%= discordEvent.time %></span>
                </h5>
                <i><%= discordEvent.description %></i>
                <div class="event-footer">
                    Join now:
                    <a href="<%= discordEvent.joinLink %>" target="_blank" >
                        <img src="<%= discordEvent.imgSrc %>"></img>
                    </a>
                </div>
            </div>
        </div>
    </div>
<% } %>

<!-- Chart stuff -->
<div class="row justify-content-center">
    <div class="dashboard-chart">
        <div class="card card-accent-info">
            <div class="card-body p-1">
                <div class="text-center axisTitle d-flex">
                    <div class="mt-1x">
                        <span class="badge clientsLabel">&nbsp;</span>
                        <span class="labelText">Players</span>
                        <span class="badge tickTimeLabel">&nbsp;</span>
                        <span class="labelText">Tick Time (at bottom is better)</span>
                    </div>

                    <div class="btn-group ml-auto">
                        <button class="btn btn-secondary btn-sm dropdown-toggle" type="button" 
                            data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" id="chartThreadSelectBtn">svMain</button>
                        <div class="dropdown-menu threadSelectDropdown bg-secondary" data-popper-placement="bottom-start">
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svMain">svMain</a>
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svSync">svSync</a>
                            <a class="dropdown-item bg-secondary text-dark" href="#" id="chartThreadSelectBtn-svNetwork">svNetwork</a>
                        </div>
                    </div>
                </div>
                
                <div id="d3-container">
                    <div class="text-center text-muted p-4" id="d3-container-message">loading chart...</div>
                </div>
            </div>
        </div>
    </div>
</div>



<div class="row justify-content-center">
    <!-- Server Control -->
    <div class="col-lg-8 col-xl-6 dashboard-card mw-col6">
        <div class="card card-accent-danger" style="min-height: 200px;">
            <div class="card-header text-center">
                <h5 class="d-inline">Server Control</h5>
            </div>
            <div class="card-body text-center align-middle">
                <button onclick="txApiFxserverControl('start')"
                    class="btn btn-outline-<%= perms.controlsClass %> btn-lg mx-auto m-2" type="button" id="ctrl-start"
                    <%= perms.controls %>>START</button> &nbsp;
                <button onclick="txApiFxserverControl('restart')"
                    class="btn btn-outline-<%= perms.controlsClass %> btn-lg mx-auto m-2" type="button"
                    id="ctrl-restart" <%= perms.controls %>>RESTART</button> &nbsp;
                <button onclick="txApiFxserverControl('stop')"
                    class="btn btn-outline-<%= perms.controlsClass %> btn-lg mx-auto m-2" type="button" id="ctrl-stop"
                    <%= perms.controls %>>STOP</button>
                <br />

                <button onclick="controlCommand('admin_broadcast')" class="btn btn-outline-dark btn-md mx-auto m-2"
                    type="button" id="ctrl-announce" <%= perms.commandMessage %>>Announcement</button>
                <button onclick="controlCommand('kick_all')" class="btn btn-outline-dark btn-md mx-auto m-2"
                    type="button" id="ctrl-kick-all" <%= perms.commandKick %>>Kick All Players</button>
                <button class="btn btn-outline-dark btn-md mx-auto m-2"
                    type="button" id="ctrl-schedule-restart" <%= perms.controls %>>Schedule Restart</button>
            </div>
        </div>
    </div>

    <!-- Status Info-->
    <div class="col-lg-8 col-xl-6 dashboard-card mw-col6">
        <div class="card card-accent-danger" style="min-height: 200px;">
            <div class="card-header text-center">
                <h5 class="d-inline">Status Info</h5>
            </div>
            <div class="card-body" id="status-card">
                Discord Bot Status:
                    <span class="badge badge-light" id="status-discord"> ?? </span> <br />
                Server Status: 
                    <span class="badge badge-light" id="status-server"> ?? </span>
                    <span class="badge badge-light" id="status-serverProcess"> ?? </span> <br />
                Next Restart:
                    <span class="font-weight-light text-warnings" id="status-nextRestartTime"> not scheduled </span>
                    <button class="btn btn-inline btn-warning d-none" type="button" id="status-nextRestartBtnCancel">
                        Cancel
                    </button>
                    <button class="btn btn-inline btn-dark d-none" type="button" id="status-nextRestartBtnEnable">
                        Enable
                    </button>
            </div>
        </div>
    </div>

</div>


<!-- Benchmark, update, pre-release messages -->
<div class="row justify-content-md-center">
    <div class="col-md-6 text-center">
        <div id="tsMessage" class="d-none">
            🏆 With <span id="tsMedianPlayerCount">?</span> median players, your server may be in the worldwide Top 500 servers. <br>
            Join <strong><a href="https://discord.gg/qmMq79D59T" target="_blank">discord.gg/txAdmin</a></strong> to check the rank and maybe get the <i>TOP SERVER</i> role.
        </div>
        <% if (fxsOutdated) { %>
            <div class="alert alert-<%= fxsOutdated.color %> border-<%= fxsOutdated.color %>" role="alert">
                <a href="<%= fxsOutdated.artifactsLink %>" target="_blank" class="alert-link"><%= fxsOutdated.message %></a>
                <br>
                <i><%= fxsOutdated.subtext %></i>
            </div>
        <% } %>
        <% if (txAdminVersion.includes('-')) { %>
            <span class="text-danger font-weight-bold">
                You are using a pre-release version of txAdmin destined for developers and beta testers only! <br>
                Your server stability might be impacted by this.
            </span>
        <% } %>
    </div>
</div>


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

<script src="https://d3js.org/d3.v6.min.js"></script>
<script type="module">
    import { drawHeatmap } from "<%= basePath %>js/txadmin/chart.js";

    //Elements & vars
    let perfData;
    const chartThreadSelectBtn = document.getElementById('chartThreadSelectBtn');
    const d3Container = document.getElementById('d3-container');
    const chartOptions = {
        // colorScheme: d3[`<%= uiTheme ? 'interpolateViridis' : 'interpolateTurbo' %>`],
        // colorScheme: d3.interpolateInferno,
        // colorScheme: d3.interpolateTurbo,
        colorScheme: d3.interpolateViridis,
    }

    //Draws the chart or sets the message
    const draw = (data) => {
        if(Array.isArray(data)){
            const tsStart = Date.now();
            const rects = drawHeatmap(d3Container, perfData, chartOptions);
            const duration = Date.now() - tsStart;
        }else if(typeof data == 'string'){
            d3Container.innerHTML = `<div class="text-center text-muted p-4" id="d3-container-message">${data}</div>`;
        }else{
            d3Container.innerHTML = `<div class="text-center text-muted p-4" id="d3-container-message">unknown data type</div>`;
        }
        d3Container.style.opacity = 1;
    }

    //Sets the chart data
    const setChartThread = async (thread) => {
        console.log(`Fetching data for ${thread}`);
        chartThreadSelectBtn.textContent = thread;
        perfData = false;
        try {
            const rawPerfData = await fetch(TX_BASE_PATH + `chartData/${thread}`);
            const parsedPerfData = JSON.parse(await rawPerfData.text());
            if(Array.isArray(parsedPerfData)){
                perfData = parsedPerfData;
                const medianPlayers = d3.median(perfData, x => x.clients);
                if(medianPlayers > 95){
                    document.getElementById('tsMedianPlayerCount').textContent = medianPlayers.toFixed(0);
                    document.getElementById('tsMessage').classList.remove('d-none');
                }
                draw(parsedPerfData);
            }else{
                if(parsedPerfData.failReason == 'not_set'){
                    draw('chart database still loading');
                }else if(parsedPerfData.failReason == 'not_enough_data'){
                    draw('Players & Performance chart will be available in an hour.');
                }else if(parsedPerfData.failReason == 'data_processing'){
                    draw('chart data processing failed');
                }else if(parsedPerfData.failReason == 'rate_limiter'){
                    draw('too many chart requests');
                }else{
                    draw('invalid chart data');
                }
            }
        } catch (error) {
            draw('failed to load chart data');
            console.log(error);
        }
    }
    setChartThread('svMain');
    document.getElementById('chartThreadSelectBtn-svMain').addEventListener('click', () => setChartThread('svMain'), false);
    document.getElementById('chartThreadSelectBtn-svSync').addEventListener('click', () => setChartThread('svSync'), false);
    document.getElementById('chartThreadSelectBtn-svNetwork').addEventListener('click', () => setChartThread('svNetwork'), false);

    //Every 2.5 minutes
    setInterval(() => {
        setChartThread(chartThreadSelectBtn.textContent);
    }, 2.5*60*1000);

    //Renders it again when resized
    let redrawTimeout;
    window.addEventListener("resize", () => {
        if(!perfData) return;
        clearTimeout(redrawTimeout);
        d3Container.style.opacity = 0.5;
        redrawTimeout = setTimeout(() => {
            draw(perfData);
        }, 250);
    });
</script>

<script>
    //============================================== Commands
    async function controlCommand(action) {
        let message = null;
        if(action == 'admin_broadcast'){
            message = await txAdminPrompt({
                modalColor: 'orange',
                confirmBtnClass: 'btn-orange',
                title: 'Announcement',
                description: 'Type the message to be broadcasted to all players.', 
                placeholder: 'the server will restart in xxx minutes...'
            });

            if(message.length <= 6){
                $.notify({ message: 'This message is too short!'}, {type: 'danger'});
                return;
            }
        }else if(action == 'kick_all'){
            message = await txAdminPrompt({
                modalColor: 'red',
                confirmBtnClass: 'btn-red',
                title: 'Kick All Players',
                description: 'Type the kick reason or leave it blank (press enter)',
                required: false,
            });
        }else{
            return;
        }
        if(message === null || message === false) return;

        const notify = $.notify({ message: 'Executing Command...' }, {});
        txAdminAPI({
            type: "POST",
            url: '/fxserver/commands',
            data: {
                action,
                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);
            }
        });
    }

    //============================================== Scheduler Stuff
    const schedulerApiCall = (action, parameter) => {
        const notify = $.notify({ message: 'Executing Command...' }, {});
        txAdminAPI({
            type: "POST",
            url: '/fxserver/schedule',
            data: {action, parameter},
            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);
            }
        });
    }
    statusCard.nextRestartBtnCancel.onclick = () => {
        schedulerApiCall('setNextSkip', true);
        statusCard.nextRestartBtnCancel.classList.add('d-none');
    }
    statusCard.nextRestartBtnEnable.onclick = () => {
        schedulerApiCall('setNextSkip', false);
        statusCard.nextRestartBtnEnable.classList.add('d-none');
    }
    document.getElementById('ctrl-schedule-restart').onclick = async () => {
        const svTimezone = '<%= serverTimezone %>';
        const timeFormatterOptions = {
            timeZone: svTimezone,
            timeStyle: 'short',
            hour12: false
        }
        const timeFormatter = new Intl.DateTimeFormat([], timeFormatterOptions);
        const serverTime = timeFormatter.format(new Date());

        const input = await txAdminPrompt({
            modalColor: 'orange',
            confirmBtnClass: 'btn-orange',
            title: 'Schedule Restart',
            placeholder: '16:15',
            description: [
                'Type in the time for the server to restart in the 24-hour format <code>HH:MM</code>.',
                'Make sure your schedule matches your server time and not your local time.',
                `<strong>Current Server Time:</strong> ${serverTime} (${svTimezone})`
            ].join('<br>'), 
        });

        const [hours, minutes] = input.split(':', 2).map(x => parseInt(x));
        if (
            typeof hours === 'undefined' || isNaN(hours) || hours < 0 || hours > 23
            || typeof minutes === 'undefined' || isNaN(minutes) || minutes < 0 || minutes > 59
        ){
            $.notify({ message: 'invalid hours:minutes'}, {type: 'danger'});
            return;
        }

        schedulerApiCall('setNextTempSchedule', input);
    }
</script>
