import {Modal} from "./Modal";
import {WebSocketEvent} from "../WebSocketEvent";
import {WebSocketPayload} from "../WebSocketPayload";
import {ButtonType} from "./ButtonType";
import {iTenderStatus} from "../iTenderStatus";
import {WebHandler} from "./WebHandler";
import {Setup} from "./Setup";
import {Pane} from "./Pane";
import {RequestType} from "../RequestType";
import {IJob} from "../database/IJob";

export class WebWebSocketHandler {
    private static socket: WebSocket;
    private static url = (window.location.protocol == "http:" ? "ws://" : "wss://") + window.location.hostname + ":3005";
    public static tareContainerUpdates: (payload: WebSocketPayload) => void;
    private static eventRegister: { event: WebSocketEvent, fn: (payload: WebSocketPayload) => void }[] = [];


    constructor(resolver: (() => void)) {
        WebWebSocketHandler.socket = new WebSocket(WebWebSocketHandler.url);
        WebWebSocketHandler.socket.onopen = (x) => {
            resolver();
            this.onOpen(x);
        };
        WebWebSocketHandler.socket.onclose = this.onClose;
        WebWebSocketHandler.socket.onerror = this.onError;
        WebWebSocketHandler.socket.onmessage = this.onMessage;

    }

    public static registerForEvent(event: WebSocketEvent, fn: (payload: WebSocketPayload) => void) {
        WebWebSocketHandler.eventRegister.push({event: event, fn: fn});
    }

    private onMessage(msgEvent: MessageEvent) {
        let payload = WebSocketPayload.parseFromBase64Json(msgEvent.data);
        if (!payload) {
            console.log("[WS] Could not parse message: ", msgEvent);
            return;
        }
        console.log("[WS] Received " + payload.event + " Event", payload);

        for (let evReg of WebWebSocketHandler.eventRegister) {
            if (evReg.event == payload.event)
                evReg.fn(payload);
        }

        switch (payload.event) {
            case WebSocketEvent.CONFIG: {
                // Incoming WebSocketStatus
                Setup.onConfigUpdate(payload);
                break;
            }

            case WebSocketEvent.STATUS: {
                let statusElement = document.getElementById("status");
                if (statusElement)
                    statusElement.innerText = payload.data.status;

                let status: iTenderStatus = payload.data.status;

                switch (status) {
                    case iTenderStatus.READY: {
                        Modal.close("start");
                        Modal.close("setup");
                        Modal.close("fill");
                        Modal.close("download");
                        if (WebHandler.currentPane != Pane.MENU)
                            WebHandler.openPane(Pane.MAIN);
                        (document.getElementById("menuBtn") as HTMLButtonElement).disabled = false;
                        break;
                    }
                    case iTenderStatus.STARTING: {
                        let modal = new Modal("start", "Willkommen!");
                        let txt = document.createElement("p");
                        txt.innerHTML = `Einen Augenblick bitte<br>iTender startet...`;
                        modal.addContent(txt);
                        modal.loader = true;
                        modal.open();
                        break;
                    }
                    case iTenderStatus.DOWNLOADING: {
                        let modal = new Modal("download", "Aktualisieren");
                        let txt = document.createElement("p");
                        txt.innerHTML = `Einen Augenblick bitte<br>iTender aktualisiert die Getränke vom Server.`;
                        modal.addContent(txt);
                        modal.loader = true;
                        modal.open();
                        break;
                    }
                    case iTenderStatus.REFRESHING: {
                        /* let modal = new Modal("refreshing", "Aktualisieren...");
                         let txt = document.createElement("p");
                         txt.innerHTML = `Einen Augenblick bitte<br>iTender aktualisiert die Getränke...`;
                         modal.addContent(txt);
                         modal.loader = true;
                         modal.open();*/
                        break;
                    }
                    case iTenderStatus.SETUP: {
                        Modal.close("start");
                        Setup.openSetup();
                        break;
                    }
                    case iTenderStatus.FILLING: {

                        let modal = new Modal("fill", "Getränk wird ausgegeben");
                        let header = document.createElement("h2");
                        header.innerText = "";

                        modal.addContent(header);

                        let txt = document.createElement("p");
                        txt.innerHTML = `Dein Cocktail wird gerade zubereitet`;
                        txt.id = "main_fillTxt";

                        let waterAnimDiv = document.createElement("div");
                        waterAnimDiv.classList.add("water");
                        modal.addContent(txt);

                        modal.addContent(waterAnimDiv);

                        let seconds = document.createElement("span");
                        seconds.innerText = "60s";
                        seconds.style.marginRight = "3%";

                        modal.addContent(seconds);

                        let ml = document.createElement("span");
                        ml.innerText = "200ml";
                        modal.addContent(ml);

                        modal.addContent(document.createElement("br"));
                        modal.addContent(document.createElement("br"));


                        let cancelBtn = document.createElement("button");
                        cancelBtn.classList.add("btn", "btn-danger");
                        cancelBtn.innerText = "Abbrechen";
                        cancelBtn.disabled = true;
                        setTimeout(() => {
                            cancelBtn.disabled = false;
                        }, 1000);
                        cancelBtn.onclick = () => {
                            cancelBtn.disabled = true;
                            txt.innerHTML = "Der Vorgang wird abgebrochen...";
                            waterAnimDiv.classList.add("waterCancel");

                            WebWebSocketHandler.send(new WebSocketPayload(WebSocketEvent.CANCEL));
                        };
                        modal.addContent(cancelBtn);

                        function riseSlowlyUp(lastNumber:number, number: number) {
                            for (let i = lastNumber; i < number; i++) {
                                setTimeout(() => {
                                    ml.innerText = i + "ml";
                                }, (number-lastNumber/1000)+i*4);
                            }
                        }

                        modal.open().then(() => {
                            WebWebSocketHandler.request(RequestType.JOB).then((payload) => {
                                let minus = 0;
                                let job = payload.data.content as IJob;
                                ml.innerText = Math.floor((job.completeAmount / job.estimatedTime) * minus) + "ml";
                                waterAnimDiv.style.setProperty("--fillTime", job.estimatedTime + "s");
                                waterAnimDiv.style.backgroundImage = `url("/images/${job.drink._id}.png")`;
                                header.innerText = job.drink.name;
                                seconds.innerText = job.estimatedTime + "s";

                                let last = 0;
                                let interval = setInterval(() => {
                                    minus++;
                                    if (minus + 1 > (job.estimatedTime as number)) {
                                        clearInterval(interval);
                                    }

                                    seconds.innerText = (Math.floor(job.estimatedTime as number - minus)) + "s";
                                    let calc = Math.floor((job.completeAmount / job.estimatedTime) * minus);
                                    riseSlowlyUp(last, calc)
                                    last = calc;
                                    //ml.innerText =  + "ml";
                                }, 1000);


                                setTimeout(() => {
                                    txt.innerHTML = "Bitte entnehme den Cocktail!";
                                    /*cancelBtn.classList.add("btn-primary");
                                    cancelBtn.classList.remove("btn-danger");
                                    cancelBtn.innerText = "Schließen";*/
                                    cancelBtn.classList.add("btn-blendout");
                                    waterAnimDiv.classList.add("waterFinished");
                                    cancelBtn.onclick = () => {
                                        modal.close();
                                    }
                                    //setTimeout(() => modal.close(), 1000 * 4.5);
                                }, job.estimatedTime * 1000);
                            });
                        });
                        break;
                    }

                }
                break;
            }

            case WebSocketEvent.DRINKS: {
                WebHandler.onDrinkUpdate(payload);
                break;
            }
        }
    }


    private onOpen(event) {
        console.log("[WS] Connected", event);

        /*let connectionElement = document.getElementById("right");
        if (connectionElement) {
            connectionElement.innerText = "Verbunden";
            connectionElement.style.color = "green";
        }*/

    }

    private onClose(event) {
        console.error("[WS] Closed!", event);
        if (event.wasClean) {
            let modal = new Modal("socketClosed", "Sitzung beendet!");
            let txt = document.createElement("p");
            txt.innerHTML = `Diese Sitzung wurde beendet, da der iTender nun an einem anderen Gerät bzw. an dem Hauptgerät gesteuert wird.<br><br>`;
            modal.addContent(txt);
            modal.addButton(ButtonType.PRIMARY, "Sitzung wiederherstellen", () => {
                window.location.reload();
            });
            modal.open();
        } else {
            let modal = new Modal("socketClosed", "Verbindungsproblem!");
            let txt = document.createElement("p");
            txt.innerHTML = `Die Benutzeroberfläche hat die Verbindung mit dem Gerät verloren.<br>Die Verbindung wird wiederhergestellt...<br>`;
            modal.addContent(txt);
            modal.loader = true;
            modal.open();
            setInterval(async () => {
                if ((await WebWebSocketHandler.checkConnection()))
                    window.location.reload();
            }, 2000);
        }

        /* let connectionElement = document.getElementById("right");
         if (connectionElement) {
             connectionElement.innerText = "Getrennt";
             connectionElement.style.color = "red";
         }*/
    }

    private static checkConnection(): Promise<boolean> {
        return new Promise(async resolve => {
            const xhr = new XMLHttpRequest();
            xhr.open("GET", '/status', true);

            //Send the proper header information along with the request
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

            xhr.onreadystatechange = () => { // Call a function when the state changes.
                if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
                    resolve(true);
                } else if (xhr.readyState == XMLHttpRequest.DONE) {
                    resolve(false);
                }
            }

            try {
                await xhr.send();
            } catch (e) {
                resolve(false);
            }

        })
    }

    private onError(event) {
        console.error("[WS] Error", event);
        /*let connectionElement = document.getElementById("right");
        if (connectionElement)
            connectionElement.innerText = "Fehler";*/
        //openModal("Einen Augenblick...", `Es wurde ein kritischer Fehler festgestellt.\nBitte warten Sie, während der Prozess neu gestartet wird...` );
        //window.location.reload();
    }

    /**
     * @return Promise<WebSocketPayload>
     * @param type
     * @param content
     */
    public static request(type: RequestType, content: any = null): Promise<WebSocketPayload> {
        console.log("Request to " + type)
        return new Promise(resolve => {
            WebWebSocketHandler.registerForEvent(WebSocketEvent.RESPONSE, (payload) => {
                if ((payload.data["type"] as RequestType) == type) {
                    resolve(payload);
                }
            });
            WebWebSocketHandler.send(new WebSocketPayload(WebSocketEvent.REQUEST, false, {
                type: type,
                content: content
            }));
        });
    }

    public static send(payload: WebSocketPayload): Promise<void> {
        console.log("[WS] Sending " + payload.event + " Event", payload);
        return new Promise(async (resolve, reject) => {
            try {
                if (this.socket && this.socket.readyState == 1) {
                    await this.socket.send(payload.toString());
                    resolve();
                }
            } catch (e) {
                /*let modal = new Modal("error", "Verbindungsfehler");
                let txt = document.createElement("p");
                txt.innerHTML = `Beim Austausch von Informationen ist ein Problem aufgetreten.<br>Falls dies öfter passieren sollte, ist der Support zu kontaktieren.`;
                modal.addContent(txt);
                await modal.open();*/
                reject();
            }
        });
    }


}