/**
 * Button and control handlers.
 * In mock mode: calls MockWebSocket.action()
 * In live mode: calls REST API
 */
var Controls = (function () {
    var currentVelocity = 40;

    // Track current state for toggles
    var isEnabled = false;
    var isRunning = false;
    var isPaused = false;
    var currentProgram = "";

    // Interaction guards: suppress state-driven updates while user input
    // is pending (waiting for backend round-trip to confirm the change)
    var sliderActive = false;
    var pendingVelocity = null;
    var pendingProgram = null;
    var velocitySendTimer = null;

    // Suppress state-driven updates for a control until the state catches up.
    // Returns true if updates should be suppressed.
    function isPending(pendingVal, stateVal) {
        if (pendingVal === null) return false;
        return stateVal !== pendingVal;
    }

    function init() {
        // Enable/Reset button
        var enableBtn = document.getElementById("btn-enable");
        if (enableBtn) {
            enableBtn.addEventListener("click", function () {
                if (enableBtn.classList.contains("disabled")) return;
                doAction(isEnabled ? "reset" : "enable");
            });
        }

        // Start/Pause button
        var startPauseBtn = document.getElementById("btn-start-pause");
        if (startPauseBtn) {
            startPauseBtn.addEventListener("click", function () {
                if (startPauseBtn.classList.contains("disabled")) return;
                if (isRunning) {
                    doAction("program/pause");
                } else {
                    doAction("program/start");
                }
            });
        }

        // Stop button
        var stopBtn = document.getElementById("btn-stop");
        if (stopBtn) {
            stopBtn.addEventListener("click", function () {
                if (stopBtn.classList.contains("disabled")) return;
                doAction("program/stop");
            });
        }

        // Reference panel
        var refPanel = document.getElementById("panel-reference");
        if (refPanel) {
            refPanel.addEventListener("click", function () {
                if (refPanel.classList.contains("disabled")) return;
                doAction("reference");
            });
        }

        // Velocity +/- buttons
        var velUp = document.getElementById("btn-vel-up");
        var velDown = document.getElementById("btn-vel-down");
        if (velUp) {
            velUp.addEventListener("click", function () { adjustVelocity(5); });
        }
        if (velDown) {
            velDown.addEventListener("click", function () { adjustVelocity(-5); });
        }

        // Velocity slider
        initSlider();

        // Safety reveal: show the slider at its default position if state
        // doesn't arrive quickly (so it doesn't stay invisible forever).
        setTimeout(function () {
            updateVelocityUI(currentVelocity);
        }, 300);

        // Program dropdown (custom widget, replaces native <select>)
        ProgramDropdown.init();
        ProgramDropdown.onChange(loadSelectedProgram);
    }

    var sliderEl = null;

    function initSlider() {
        sliderEl = document.getElementById("slider-track");
        if (!sliderEl) return;
        var fill = document.getElementById("slider-fill");
        var thumb = document.getElementById("slider-thumb");

        function startDrag() {
            sliderActive = true;
            if (fill) fill.style.transition = "none";
            if (thumb) thumb.style.transition = "none";
        }

        function endDrag() {
            sliderActive = false;
            if (fill) fill.style.transition = "";
            if (thumb) thumb.style.transition = "";
            // Send final value immediately
            clearTimeout(velocitySendTimer);
            velocitySendTimer = null;
            sendVelocity(currentVelocity);
        }

        // Touch events
        sliderEl.addEventListener("touchstart", function (e) {
            startDrag();
            setVelocityFromSlider(e.touches[0].clientX);
        });
        sliderEl.addEventListener("touchmove", function (e) {
            if (!sliderActive) return;
            e.preventDefault();
            setVelocityFromSlider(e.touches[0].clientX);
        });
        document.addEventListener("touchend", function () {
            if (sliderActive) endDrag();
        });

        // Mouse events
        sliderEl.addEventListener("mousedown", function (e) {
            startDrag();
            setVelocityFromSlider(e.clientX);

            var onMove = function (ev) {
                if (sliderActive) setVelocityFromSlider(ev.clientX);
            };
            document.addEventListener("mousemove", onMove);
            document.addEventListener("mouseup", function () {
                endDrag();
                document.removeEventListener("mousemove", onMove);
            }, { once: true });
        });
    }

    function setVelocityFromSlider(clientX) {
        if (!sliderEl) return;
        var rect = sliderEl.getBoundingClientRect();
        var pct = Math.round(((clientX - rect.left) / rect.width) * 100);
        pct = Math.max(0, Math.min(100, pct));
        setVelocityAbsolute(pct);
    }

    function setVelocityAbsolute(value) {
        currentVelocity = Math.max(0, Math.min(100, value));
        pendingVelocity = currentVelocity;

        // Update display immediately
        updateVelocityUI(currentVelocity);

        // Throttle backend calls (send at most every 100ms)
        if (!velocitySendTimer) {
            velocitySendTimer = setTimeout(function () {
                velocitySendTimer = null;
                sendVelocity(currentVelocity);
            }, 100);
        }
    }

    function updateVelocityUI(vel) {
        var el = document.getElementById("velocity-display");
        if (el) el.textContent = Number(vel).toFixed(1) + "%";
        var fill = document.getElementById("slider-fill");
        var thumb = document.getElementById("slider-thumb");
        // Map 0–100% onto the usable track range so the thumb stays fully
        // inside. Inset = half thumb (11px) + 2px padding.
        var track = document.getElementById("slider-track");
        var trackW = track ? track.offsetWidth : 200;
        var inset = 13;
        var usable = trackW - 2 * inset;
        var px = inset + (vel / 100) * usable;
        // Fill ends at the thumb's centre (thumb uses translate(-50%) so
        // `left` IS the centre), so the fill/thumb alignment stays constant
        // across the whole range instead of drifting at the extremes.
        if (fill) fill.style.width = px + "px";
        if (thumb) thumb.style.left = px + "px";
        if (Number.isFinite(Number(vel))) {
            var inner = document.querySelector(".velocity-inner");
            if (inner) inner.classList.add("ready");
        }
    }

    function sendVelocity(vel) {
        if (Config.MOCK_MODE) {
            MockWebSocket.setVelocity(vel);
        } else {
            fetch(Config.API_URL + "/velocity", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ velocity: vel })
            })
                .then(function (r) { return r.json(); })
                .catch(function (err) {
                    console.error("Set velocity error:", err);
                });
        }
    }

    function doAction(action) {
        if (Config.MOCK_MODE) {
            MockWebSocket.action(action);
        } else {
            postAction(action);
        }
    }

    function postAction(action) {
        fetch(Config.API_URL + "/" + action, { method: "POST" })
            .then(function (r) { return r.json(); })
            .then(function (data) {
                if (!data.ok) {
                    console.warn("Action " + action + " failed:", data.error);
                }
            })
            .catch(function (err) {
                console.error("Action " + action + " error:", err);
            });
    }

    var pendingProgramTimer = null;

    function loadSelectedProgram(program) {
        program = program || "";
        pendingProgram = program;
        clearTimeout(pendingProgramTimer);
        pendingProgramTimer = setTimeout(function () { pendingProgram = null; }, 5000);

        if (Config.MOCK_MODE) {
            MockWebSocket.loadProgram(program);
            return;
        }

        fetch(Config.API_URL + "/program/load", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ program: program })
        })
            .then(function (r) { return r.json(); })
            .then(function (data) {
                if (!data.ok) {
                    console.warn("Load program failed:", data.error);
                }
            })
            .catch(function (err) {
                console.error("Load program error:", err);
            });
    }

    function adjustVelocity(delta) {
        setVelocityAbsolute(currentVelocity + delta);
    }

    var PLACEHOLDER_ITEM = { value: "", label: "-- No program selected --" };

    function loadProgramList() {
        if (Config.MOCK_MODE) {
            ProgramDropdown.setItems([
                PLACEHOLDER_ITEM,
                { value: "Mein_Testprogramm_1.xml", label: "Mein_Testprogramm_1.xml" },
                { value: "Mein_Testprogramm_2.xml", label: "Mein_Testprogramm_2.xml" },
                { value: "Mein_Testprogramm_3.xml", label: "Mein_Testprogramm_3.xml" }
            ]);
            return;
        }

        fetch(Config.API_URL + "/programs")
            .then(function (r) { return r.json(); })
            .then(function (data) {
                var programs = data.programs || [];
                var items = [PLACEHOLDER_ITEM];
                for (var i = 0; i < programs.length; i++) {
                    items.push({ value: programs[i], label: programs[i] });
                }
                ProgramDropdown.setItems(items);
                // Sync with currently loaded program
                var syncTarget = pendingProgram || currentProgram;
                if (syncTarget) {
                    ProgramDropdown.setValue(syncTarget);
                }
            })
            .catch(function (err) {
                console.error("Load program list error:", err);
            });
    }

    function syncProgramSelect() {
        if (isPending(pendingProgram, currentProgram)) return;
        pendingProgram = null;
        var target = currentProgram || "";
        if (ProgramDropdown.getValue() !== target) {
            ProgramDropdown.setValue(target);
        }
    }

    function updateVelocityFromState(velocity) {
        if (sliderActive) return;
        if (isPending(pendingVelocity, velocity)) return;
        pendingVelocity = null;
        currentVelocity = velocity;
        updateVelocityUI(velocity);
    }

    function updateFromState(state) {
        if (!state.robot) return;

        isEnabled = state.robot.isEnabled;

        if (state.motion && state.motion.motionProgram) {
            isRunning = state.motion.motionProgram.runState === "running";
            isPaused = state.motion.motionProgram.runState === "paused";

            // Track current program (strip path prefix)
            var prog = state.motion.motionProgram.currentProgram || "";
            var slashIndex = prog.lastIndexOf("/");
            currentProgram = slashIndex >= 0 ? prog.substring(slashIndex + 1) : prog;
        }
    }

    return {
        init: init,
        loadProgramList: loadProgramList,
        updateVelocityFromState: updateVelocityFromState,
        updateFromState: updateFromState,
        syncProgramSelect: syncProgramSelect
    };
})();
