/**
 * Config-driven tile renderer.
 * Reads tile definitions from config.json, creates DOM elements,
 * and updates them on each WebSocket state push.
 */
var Tiles = (function () {
    var tileConfig = null;

    function load(callback) {
        if (Config.MOCK_MODE) {
            // In mock mode: use default config
            tileConfig = getDefaultConfig();
            renderAll();
            if (callback) callback();
            return;
        }

        fetch(Config.API_URL + "/config")
            .then(function (r) { return r.json(); })
            .then(function (cfg) {
                tileConfig = cfg.tiles || getDefaultConfig();
                renderAll();
                if (callback) callback();
            })
            .catch(function () {
                tileConfig = getDefaultConfig();
                renderAll();
                if (callback) callback();
            });
    }

    function getDefaultConfig() {
        return {
            sidebar: [
                {
                    id: "hardware",
                    title: "Hardware",
                    dataPath: "robot.hardwareState",
                    accentColor: {
                        rules: [
                            { value: "NoError", color: "green" },
                            { default: true, color: "red" }
                        ]
                    },
                    fields: [
                        { label: "Mode", dataPath: "system.isSimulation", format: "simulation" },
                        { label: "Status", dataPath: "robot.hardwareState", colorMode: "status", displayMap: { "NoError": "No error" } }
                    ]
                },
                {
                    id: "kinematics",
                    title: "Kinematics",
                    dataPath: "robot.kinematicState",
                    accentColor: {
                        rules: [
                            { value: "normal", color: "green" },
                            { default: true, color: "red" }
                        ]
                    },
                    fields: [
                        { label: "Status", dataPath: "robot.kinematicState", colorMode: "status", displayMap: { "normal": "OK" } },
                        { label: "Speed", dataPath: "robot.cartesianVelocity", format: "fixed1", suffix: " mm/s", colorMode: "dim" }
                    ]
                },
                {
                    id: "robot",
                    title: "Robot",
                    dataPath: "system.robotType",
                    accentColor: {
                        rules: [
                            { default: true, color: "green" }
                        ]
                    },
                    fields: [
                        { label: "Model", dataPath: "system.robotType" },
                        { label: "Firmware", dataPath: "system.version", colorMode: "dim" }
                    ]
                },
                {
                    id: "motion",
                    title: "Motion Program",
                    dataPath: "motion.motionProgram.runState",
                    accentColor: {
                        rules: [
                            { default: true, color: "green" }
                        ]
                    },
                    fields: [
                        { label: "Command", dataPath: "motion.motionProgram.currentCommandIndex", format: "command", colorMode: "dim" }
                    ]
                }
            ]
        };
    }

    function renderAll() {
        renderGroup("sidebar-tiles", tileConfig.sidebar || []);
        renderGroup("bottom-sheet-tiles", tileConfig.sidebar || [], "bs-");
    }

    function renderGroup(containerId, tiles, prefix) {
        var container = document.getElementById(containerId);
        if (!container) return;
        container.innerHTML = ''; // Clear existing
        for (var i = 0; i < tiles.length; i++) {
            container.appendChild(createTile(tiles[i], prefix || ""));
        }
    }

    function createTile(def, prefix) {
        var tile = document.createElement("div");
        tile.className = "tile";
        tile.id = prefix + "tile-" + def.id;

        var title = document.createElement("div");
        title.className = "tile-header";
        title.textContent = def.title || def.id;
        tile.appendChild(title);

        var content = document.createElement("div");
        content.className = "tile-content";

        var fields = def.fields || [];
        for (var i = 0; i < fields.length; i++) {
            var field = fields[i];
            var row = document.createElement("div");
            row.className = "tile-field";

            var label = document.createElement("span");
            label.className = "tile-field-label";
            label.textContent = field.label;
            row.appendChild(label);

            var value = document.createElement("span");
            value.className = "tile-field-value";
            value.id = prefix + "field-" + def.id + "-" + i;
            value.textContent = "--";
            row.appendChild(value);

            content.appendChild(row);
        }

        tile.appendChild(content);
        return tile;
    }

    function resolve(obj, path) {
        if (!obj || !path) return undefined;
        var parts = path.split(".");
        var current = obj;
        for (var i = 0; i < parts.length; i++) {
            if (current === undefined || current === null) return undefined;
            current = current[parts[i]];
        }
        return current;
    }

    function formatValue(val, field, state) {
        if (val === undefined || val === null) return "--";

        var format = field.format;
        var suffix = field.suffix || "";

        // Apply displayMap first (e.g. "NoError" -> "No error")
        if (field.displayMap && field.displayMap[String(val)] !== undefined) {
            val = field.displayMap[String(val)];
        }

        if (format === "simulation") {
            return val ? "Simulation" : "Hardware";
        }
        if (format === "fixed0") {
            var num = Number(val);
            if (!isNaN(num)) return num.toFixed(0) + suffix;
        }
        if (format === "fixed1") {
            var num = Number(val);
            if (!isNaN(num)) return num.toFixed(1) + suffix;
        }
        if (format === "fixed2") {
            var num = Number(val);
            if (!isNaN(num)) return num.toFixed(2) + suffix;
        }
        if (format === "command") {
            var total = resolve(state, "motion.motionProgram.commandCount") || 0;
            return (val + 1) + " / " + total;
        }

        // Default: format numbers to 1 decimal
        var num = Number(val);
        if (typeof val === "number" || (val !== "" && !isNaN(num))) {
            return num.toFixed(1) + suffix;
        }

        return String(val) + suffix;
    }

    function update(state) {
        if (!tileConfig) return;
        updateGroup(tileConfig.sidebar || [], state, "");
        updateGroup(tileConfig.sidebar || [], state, "bs-");
    }

    function updateGroup(tiles, state, prefix) {
        for (var i = 0; i < tiles.length; i++) {
            var def = tiles[i];
            var tileColor = updateTileAccent(def, state, prefix);
            var fields = def.fields || [];
            for (var j = 0; j < fields.length; j++) {
                var field = fields[j];
                var el = document.getElementById(prefix + "field-" + def.id + "-" + j);
                if (!el) continue;
                var val = resolve(state, field.dataPath);
                el.textContent = formatValue(val, field, state);

                // Apply value color classes
                el.classList.remove("val-ok", "val-err", "val-dim");
                if (field.colorMode === "dim") {
                    el.classList.add("val-dim");
                } else if (field.colorMode === "status") {
                    // Color follows tile accent: green=ok, red=error
                    if (tileColor === "green") {
                        el.classList.add("val-ok");
                    } else if (tileColor === "red") {
                        el.classList.add("val-err");
                    }
                }
            }
        }
    }

    function updateTileAccent(def, state, prefix) {
        if (!def.accentColor || !def.accentColor.rules) return "";
        var tileEl = document.getElementById(prefix + "tile-" + def.id);
        if (!tileEl) return "";

        var val = resolve(state, def.dataPath);
        var color = "";
        var rules = def.accentColor.rules;
        for (var i = 0; i < rules.length; i++) {
            if (rules[i].default) {
                color = rules[i].color;
            } else if (String(val) === String(rules[i].value)) {
                color = rules[i].color;
                break;
            }
        }

        // Remove old accent classes
        tileEl.classList.remove("ok", "warning", "error");
        if (color === "green") {
            tileEl.classList.add("ok");
        } else if (color === "orange") {
            tileEl.classList.add("warning");
        } else if (color === "red") {
            tileEl.classList.add("error");
        }

        return color;
    }

    return {
        load: load,
        update: update
    };
})();
