<?php

namespace onespace\tools\widgets\helpers;

use yii\base\Widget;
use yii\web\View;

final class AsyncBlockJS extends Widget {

    public $pos;

    public function init(): void {
        $this->pos ??= View::POS_READY;

        $js = <<<JS
        document.OneSpace = {
            AsyncManager: {
                pjaxContainers: $("div[data-pjax-container]"),
                pjaxInProg: false,
                refreshHistory: [],
                containerRefreshCalls: [],
                cancelling: false
            }
        }
        
        async function runPjax() {
            let dAsyncMngr = document.OneSpace.AsyncManager;
            dAsyncMngr.pjaxInProg = true;
            // console.debug("building reload calls");
            dAsyncMngr.containerRefreshCalls = []; // reset call
            dAsyncMngr.pjaxContainers.each((i, ele) => {
                if (ele.getAttribute("needs-reload") == "true") {
                    // console.debug("building reload for " + ele.getAttribute("id"));
                    dAsyncMngr.containerRefreshCalls.push(() => {
                        // console.debug("reloading " + ele.getAttribute("id"));
                        return $.pjax.reload({ container: "#" + ele.getAttribute("id") })
                            .then(() => { $.pjax.xhr = null; })
                            .catch(e => {
                                // console.debug("inner");
                                // console.debug(JSON.stringify(e));
                            });
                    });
                    ele.setAttribute("needs-reload", false);
                // } else {
                    // console.debug("reload not set: " + ele.getAttribute("needs-reload"));
                }
            });
            releaseQueue(dAsyncMngr.containerRefreshCalls, () => {
                dAsyncMngr.pjaxInProg = false;
                if (!dAsyncMngr.cancelling) { checkForBrokenCharts() }
            });
        } // will change the value of this when adding to pjax queue and trigger the onchange event
        
        let triggerEle = document.createElement("input");
        triggerEle.setAttribute("hidden", true);
        triggerEle.value = "";
        triggerEle.setAttribute("id", "checkServer");
        document.body.appendChild(triggerEle);
        $("#checkServer").change(() => {
            // console.debug("responding to trigger"); 
            if ($("#checkServer").val() != "") {
                let pjaxInProg = document.OneSpace.AsyncManager.pjaxInProg ?? false; if (!pjaxInProg) { runPjax(); }
                $("#checkServer").val("");
                // console.debug($("#checkServer").val());
            }
        });
        document.OneSpace.AsyncManager.abortPjaxRequests = () => {
            document.OneSpace.AsyncManager.cancelling = true;
            if ($.pjax && $.pjax.xhr && $.pjax.xhr.readyState < 4) {
                // console.debug("cancelling server request before redirect");
                $.pjax.xhr.onreadystatechange = $.noop;
                $.pjax.xhr.abort();
            } else {
                // console.debug("Should be able to redirect straight away");
            }
        };
        if ($.pjax) {
            $("a[href]:not([target=\"_blank\"]):not([href^=\"#\"]):not([href^=\"javascript:void(0)\"])").on("pointerup", document.OneSpace.AsyncManager.abortPjaxRequests);
        }
        
        
        function releaseQueue(exeQueue, after) {
            let dAsyncMngr = document.OneSpace.AsyncManager;
            // console.debug(exeQueue.length);
            if (exeQueue.length > 0 && !dAsyncMngr.cancelling) {
                let request = exeQueue.shift();
                dAsyncMngr.refreshHistory.push(
                    request().done(() => {
                        if (exeQueue.length == 0) {
                            after();
                        }
                        if (!dAsyncMngr.cancelling) {
                            return releaseQueue(exeQueue, after);
                        }
                        else {
                            // console.debug("Preventing queue continuation due to redirection");
                        }
                    }).catch(e => { 
                        // console.debug("outer"); 
                        // console.debug(JSON.stringify(e)); 
                    })
                );
                return dAsyncMngr.refreshHistory[dAsyncMngr.refreshHistory.length - 1];
            }
        }
        
        
        function checkForBrokenCharts() {
            return; // Not needed anymore
        }
        $(document).on("pjax:timeout", function (event) {
            // console.debug("timeout occured");
            try {
                // console.debug(event.target ?? "no target found");
            } catch (err) { console.error(err); }
            // Prevent default timeout redirection behavior
            event.preventDefault()
        });
        document.OneSpace.AsyncManager.pjaxStartLogic = () => {
            document.OneSpace.AsyncManager.pjaxContainers.each((i, ele) => { ele.setAttribute("needs-reload", true) });
            // console.debug("Server data retrieval triggering");
            $("#checkServer").val("true").trigger("change");
        }
        if (typeof ($) === "undefined") {
            setTimeout(document.OneSpace.AsyncManager.pjaxStartLogic, 300);
        } else {
            $(document.OneSpace.AsyncManager.pjaxStartLogic);
        }
        
        JS;

        $view = $this->getView();
        $view->registerJs($js, $this->pos);
    }
}

/**
 * KEPT FOR REFERENCE
 * 
 * function checkForBrokenCharts() {
 *     setTimeout(() => {
 *         // console.debug("checking for broken Charts");
 *         let pjaxRef = "div[data-pjax-container]";
 *         // check for instances where chart container is empty but script for chart exists
 *         let emptyCharts = $(pjaxRef + " div[id]:empty");//chart needs an id
 *         if (emptyCharts.length > 0) {
 *             // cycle through and get a script tag that loads the highchart
 *             emptyCharts.each((i, ele) => {
 *                 let container = $(ele).closest(pjaxRef);
 *                 let script = container.find("script");
 *                 let scriptText = script.text();
 *                 // confirm if its a Highcharts chart attempting to be created
 *                 if (script.length > 0 && scriptText.indexOf("Highcharts") != -1) {
 *                     let startPosRef = "Highcharts.chart(";
 *                     let startPos = scriptText.indexOf(startPosRef) + startPosRef.length;
 *                     let endPos = scriptText.indexOf(ele.id + "\'), {") + (ele.id + "\')").length;
 *                     let currentContainer = scriptText.substring(startPos, endPos);
 *                     // Set the container as it has crash before when conflicting ids exist. 
 *                     // so make it more specific to that id in this pjax block
 *                     script.text(scriptText.replace("Highcharts.chart(" + currentContainer, "Highcharts.chart(document.querySelector('#" + container.attr("id") + ' #' + ele.id + "')"));
 *                     eval(script.text());
 *                 }
 *             });
 *         }
 *     }, 300);
 * }
 */