import {WebSocketPayload} from "../../WebSocketPayload";
import debug from "debug";
import {WebSocketHandler} from "../../WebSocketHandler";
import {iTender} from "../../iTender";
import {iTenderStatus} from "../../iTenderStatus";
import {WebSocketEvent} from "../../WebSocketEvent";
import Container from "../../database/Container";
import {SensorType} from "../../SensorType";
import {Settings} from "../../Settings";
import Ingredient from "../../database/Ingredient";
import {RequestType} from "../../RequestType";
import {IJob} from "../../database/IJob";

const express = require('express');
const router = express.Router();


const log = debug("itender:websocket");

router.ws('/', async (ws, req, next) => {
    log("Incoming websocket connection...");

    if (WebSocketHandler.ws) {
        iTender.toggleTare(false);
        WebSocketHandler.ws.close(1001);
    }
    WebSocketHandler.ws = ws;

    await WebSocketHandler.sendRunningConfig();
    await WebSocketHandler.sendContainers();
    await WebSocketHandler.sendStatus();
    await WebSocketHandler.sendDrinks();


    ws.on('message', async (raw, bool) => {
        let msg = WebSocketPayload.parseFromBase64Json(raw);
        // If message is null, close the socket because it could not be decompiled
        if (!msg) {
            ws.close(1011);
            return;
        }



        switch (msg.event) {
            case WebSocketEvent.TARE: {
                if (msg.data["state"] == true) {
                    iTender.toggleTare(true);
                } else {
                    iTender.toggleTare(false);
                }
                break;
            }
            case WebSocketEvent.CONTAINERS: {
                let data = msg.data as { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; volume: number; }[];
                await Container.deleteMany({});

                let i = 0;
                for (let c of data) {
                    let container = new Container();
                    container.slot = i;
                    container.volume = c.volume;
                    container.pumpPin = c.pumpPin;
                    container.sensorType = c.sensorType;
                    container.sensorPin1 = c.sensor1;
                    container.sensorPin2 = c.sensor2;
                    container.enabled = true;
                    await container.save();
                    i++;
                }
                break;
            }

            case WebSocketEvent.CONTAINER_UPDATE: {
                let container = await Container.findById(msg.data["container"]);
                if (!container) break;

                let ingredient;
                if (msg.data["ingredient"] != null) {
                    ingredient = await Ingredient.findById(msg.data["ingredient"]);
                    if (!ingredient)
                        ingredient = undefined;
                }

                container.filled = parseInt(msg.data["filled"]);
                container.content = ingredient;

                await container.save();

                await iTender.refreshDrinks();
                break;
            }

            case WebSocketEvent.CONFIG: {
                // ToDo
                console.log("New Settings:", msg.data);
                // Danach setup modus us
                for (const [key, value] of Object.entries(msg.data)) {
                    Settings.set(key, value);
                }

                Settings.setupDone = true;
                break;
            }

            case WebSocketEvent.SETUP: {
                if ((msg.data as boolean)) {
                    iTender.setStatus(iTenderStatus.SETUP);
                } else {
                    if (Settings.setupDone) {
                        iTender.setStatus(iTenderStatus.READY);
                        await WebSocketHandler.sendRunningConfig();
                    }
                }
                await WebSocketHandler.sendContainers();
                break;
            }

            case WebSocketEvent.REQUEST: {

                switch (msg.data["type"] as RequestType) {
                    case RequestType.STATS: {
                        await WebSocketHandler.sendStats();
                        break;
                    }
                    case RequestType.CONTAINERS: {
                        WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Container.find().sort({"slot": 1}).populate("content")));
                        break;
                    }
                    case RequestType.INGREDIENTS: {
                        WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Ingredient.find().sort({"name": 1})));
                        break;
                    }
                    case RequestType.STARTFILL: {
                        let job: IJob | null = null;
                        try {
                            job = await iTender.onReceiveFill(msg.data["content"]);
                        } catch (e: any) {
                            console.error(e);
                        }
                        WebSocketHandler.answerRequest(msg.data["type"] as RequestType, {success: (!!job), job: job});
                        break;
                    }
                    case RequestType.JOB: {
                        WebSocketHandler.answerRequest(msg.data["type"] as RequestType, iTender.currentJob);
                        break;
                    }

                }
                break;
            }

            default: {
                log("WebSocketHandler does not know how to handle " + msg.event + " Event");
            }
        }
    });

});

module.exports = router;
