

class RelayOverlay {

    constructor(parent, relay) {
        this.parent = parent;
        this.relay = relay;
        this.uuid = relay.uuid;
        this.sockets = parent.sockets;

        this.init_controls();
    }

    init_controls() {
        this.duration_box = sId('duration-'+this.uuid);
        this.start_box = sId('start-'+this.uuid);
        this.stop_box = sId('stop-'+this.uuid);
        this.flow_box = sId('flow-'+this.uuid);
        this.ts_box = sId('ts-'+this.uuid);
        this.rate_box = sId('rate-'+this.uuid);
        this.remaining_box = sId('remaining-'+this.uuid);
        this.duration_value = parseInt(this.duration_box.value);
        this.relay_state = 0;
        this.flow = 0.00;

        this.start_box.onclick = () => {
            this.start();
        };
        this.stop_box.onclick = () => {
            this.stop();
        };
        this.duration_box.onchange = () => {
            this.duration_value = parseInt(this.duration_box.value);
        }
    }

    update(payload) {
        if (payload.topic === "status") {
            this.relay_state = payload.relay_state;
            this.flow = parseFloat(payload.flow.toFixed(2));
            this.rate = parseFloat(payload.rate.toFixed(2));

            this.start_box.disabled = this.relay_state === 1;
            this.stop_box.disabled = this.relay_state === 0;

            if (payload.remaining>0) {
                this.remaining_box.textContent = `${payload.remaining} s restante(s)`;
            } else {
                this.remaining_box.textContent = "";
            }
            this.ts_box.textContent = new Date(payload.ts * 1000).toLocaleTimeString();
            this.duration_box.value = this.duration_value;
            this.flow_box.textContent = this.flow;
            this.rate_box.textContent = this.rate;
        }
    }

    start()         { this._send({ type: 'relay', topic: "start", value: this.duration_value }); }
    stop()          { this._send({ type: 'relay', topic: "stop" });     }
    status()        { this._send({ type: 'relay', topic: "status" });   }
    halt()          { this._send({ type: 'relay', topic: "halt" });     }
    restart()       { this._send({ type: 'relay', topic: "restart" });  }
    _send(message)  { this.sockets[this.uuid].send(message); }
}

class RelayManager {
    constructor(container, relay) {
        this.container = container;
        this.relay = relay;
        this.overlays = {};
        this.sockets = {};
        this.init_controls();
    }

    init_controls() {
        this.all_relay_state = 0;
        this.startall_box = sId('start-all');
        this.stopall_box = sId('stop-all');
        this.flow_box = sId('flow-all');

        this.startall_box.onclick = () => {
            this.all_relay_state = 1;
            this._broadcast({ type: 'relay-multi', action: "start" });
        };
        this.stopall_box.onclick = () => {
            this.all_relay_state = 0;
            this._broadcast({ type: 'relay-multi', action: "stop" });
        };
        this.update_button();
    }

    async start() {
        for (const relay of this.relay) {
            const overlay = new RelayOverlay(this, relay);
            this.overlays[relay.uuid] = overlay;
        }
    }

    registerSocket(uuid, socket) {
        this.sockets[uuid] = socket;
    }

    update_button() {
        this.startall_box.disabled = this.all_relay_state === 1;
        this.stopall_box.disabled = this.all_relay_state === 0;
    }

    flow_update() {
        let total_flow = 0.00;
        for (const relay of this.relay) {
            const overlay = this.overlays[relay.uuid];
            if (overlay) {
                total_flow =  total_flow + overlay.flow;
            }
        }
        this.flow_box.textContent = total_flow.toFixed(2);
    }

    update(uuid, payload) {
        const overlay = this.overlays[uuid];
        if (overlay) {
            overlay.update(payload);
        }
    }

    _broadcast(message) {
        if (message.type === 'relay-multi') {
            const action = message.action;
            this.update_button();
            for (const relay of this.relay) {
                const overlay = this.overlays[relay.uuid];
                overlay[action]();
            }
        }
    }
}

class MetadataSocket {
    constructor(url, uuid) {
        this.url = url;
        this.uuid = uuid;
        this.ws = null;
        this.manager = null;
        this.reconnectDelay = 1000;
        this.shouldReconnect = true;
        this.reconnect = false;
    }

    setOverlayManager(manager) {
        this.manager = manager;
    }

    connect() {
        this.ws = new WebSocket(this.url);

        this.ws.onmessage = (event) => {
            const data = JSON.parse(event.data);
            this.manager.update(this.uuid, data);
            this.manager.flow_update();
        };

        this.ws.onopen = (event) => {
            const overlay = this.manager.overlays[this.uuid];
            if (overlay && !this.reconnect)
                overlay['status']();
            this.reconnect = false;
        };

        this.ws.onclose = () => {
            console.warn(`WebSocket closed ${this.uuid}`);
            if (this.shouldReconnect) {
                this.reconnect = true;
                setTimeout(() => {
                    console.log("Reconnect WebSocket...");
                    this.connect();
                }, this.reconnectDelay);
            }
        };
    }

    send(obj) {
        if (this.ws?.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(obj));
        }
    }
}