// Zone management JavaScript
let currentZoneId = null;
let brightnessSendTimeout = null;

function clamp255(n) {
    const v = parseInt(n, 10);
    if (Number.isNaN(v)) return null;
    return Math.max(0, Math.min(255, v));
}

function applyBrightnessSliders(val) {
    const v = clamp255(val);
    if (v === null) return;
    const headerSlider = document.getElementById("header-brightness-slider");
    const menuSlider = document.getElementById("menu-brightness-slider");
    if (headerSlider) headerSlider.value = String(v);
    if (menuSlider) menuSlider.value = String(v);
}

async function saveZoneBrightnessToServer(zoneId, val) {
    if (!zoneId) return;
    try {
        const res = await fetch(`/zones/${zoneId}`, {
            method: "PUT",
            headers: { "Content-Type": "application/json", Accept: "application/json" },
            credentials: "same-origin",
            body: JSON.stringify({ brightness: val }),
        });
        if (!res.ok) {
            const err = await res.json().catch(() => ({}));
            console.warn("zone brightness save failed:", err.error || res.status);
        }
    } catch (e) {
        console.warn("zone brightness save failed:", e);
    }
}

function sendZoneBrightness(zoneId, value) {
    if (!zoneId) return;
    const val = Math.max(0, Math.min(255, parseInt(value, 10) || 0));
    const headerSlider = document.getElementById('header-brightness-slider');
    const menuSlider = document.getElementById('menu-brightness-slider');
    if (headerSlider && String(headerSlider.value) !== String(val)) {
        headerSlider.value = String(val);
    }
    if (menuSlider && String(menuSlider.value) !== String(val)) {
        menuSlider.value = String(val);
    }
    if (brightnessSendTimeout) {
        clearTimeout(brightnessSendTimeout);
    }
    brightnessSendTimeout = setTimeout(() => {
        (async () => {
            try {
                await saveZoneBrightnessToServer(zoneId, val);
                const section = document.querySelector('.presets-section[data-zone-id]');
                const names = typeof window.parseTabDeviceNames === 'function'
                    ? window.parseTabDeviceNames(section)
                    : [];
                const targetMacs =
                    names.length > 0 &&
                    typeof window.tabsManager !== 'undefined' &&
                    typeof window.tabsManager.resolveTabDeviceMacs === 'function'
                        ? await window.tabsManager.resolveTabDeviceMacs(names)
                        : [];
                if (typeof window.postDriverSequence === 'function') {
                    await window.postDriverSequence([{ v: '1', b: val, save: true }], targetMacs, 0);
                    return;
                }
                // Fallback to raw websocket sender if presets.js helper isn't available yet.
                if (typeof window.sendEspnowRaw === 'function') {
                    window.sendEspnowRaw({ v: '1', b: val, save: true });
                }
            } catch (err) {
                console.error('Failed to send brightness via driver sequence:', err);
            }
        })();
    }, 150);
}

const isEditModeActive = () => {
    const toggle = document.querySelector('.ui-mode-toggle');
    return !!(toggle && toggle.getAttribute('aria-pressed') === 'true');
};

// Get current zone from cookie
function getCurrentZoneFromCookie() {
    const cookies = document.cookie.split(';');
    for (let cookie of cookies) {
        const [name, value] = cookie.trim().split('=');
        if (name === 'current_zone') {
            return value;
        }
    }
    return null;
}

async function fetchDevicesMap() {
    try {
        const response = await fetch("/devices", { headers: { Accept: "application/json" } });
        if (!response.ok) return {};
        const data = await response.json();
        return data && typeof data === "object" ? data : {};
    } catch (e) {
        console.error("fetchDevicesMap:", e);
        return {};
    }
}

/** Registry MACs for zone device names (order matches zone names; skips unknown names). */
async function resolveZoneDeviceMacs(zoneNames) {
    const dm = await fetchDevicesMap();
    const rows = namesToRows(Array.isArray(zoneNames) ? zoneNames : [], dm);
    const macs = rows.map((r) => r.mac).filter(Boolean);
    return [...new Set(macs)];
}

function namesToRows(zoneNames, devicesMap) {
    const usedMacs = new Set();
    const list = Array.isArray(zoneNames) ? zoneNames : [];
    return list.map((name) => {
        const n = String(name || "").trim();
        const matches = Object.entries(devicesMap || {}).filter(
            ([mac, d]) => d && String((d.name || "").trim()) === n && !usedMacs.has(mac),
        );
        if (matches.length === 0) {
            return { mac: null, name: n || "unknown" };
        }
        const [mac] = matches[0];
        usedMacs.add(mac);
        return { mac, name: n };
    });
}

function rowsToNames(rows) {
    return (rows || []).map((r) => String(r.name || "").trim()).filter((n) => n.length > 0);
}

function renderZoneDevicesEditor(containerEl, rows, devicesMap) {
    if (!containerEl) return;
    containerEl.innerHTML = "";
    const entries = Object.entries(devicesMap || {}).sort(([a], [b]) => a.localeCompare(b));

    rows.forEach((row, idx) => {
        const div = document.createElement("div");
        div.className = "zone-device-row profiles-row";
        const label = document.createElement("span");
        label.className = "zone-device-row-label";
        const strong = document.createElement("strong");
        strong.textContent = row.name || "—";
        label.appendChild(strong);
        label.appendChild(document.createTextNode(" "));
        const sub = document.createElement("span");
        sub.className = "muted-text";
        sub.textContent = row.mac ? row.mac : "(not in registry)";
        label.appendChild(sub);

        const rm = document.createElement("button");
        rm.type = "button";
        rm.className = "btn btn-danger btn-small";
        rm.textContent = "Remove";
        rm.addEventListener("click", () => {
            rows.splice(idx, 1);
            renderZoneDevicesEditor(containerEl, rows, devicesMap);
        });
        div.appendChild(label);
        div.appendChild(rm);
        containerEl.appendChild(div);
    });

    const macsInRows = new Set(rows.map((r) => r.mac).filter(Boolean));
    const addWrap = document.createElement("div");
    addWrap.className = "zone-devices-add profiles-actions";
    const sel = document.createElement("select");
    sel.className = "zone-device-add-select";
    sel.appendChild(new Option("Add device…", ""));
    entries.forEach(([mac, d]) => {
        if (macsInRows.has(mac)) return;
        const labelName = d && d.name ? String(d.name).trim() : "";
        const optLabel = labelName ? `${labelName} — ${mac}` : mac;
        sel.appendChild(new Option(optLabel, mac));
    });
    const addBtn = document.createElement("button");
    addBtn.type = "button";
    addBtn.className = "btn btn-primary btn-small";
    addBtn.textContent = "Add";
    addBtn.addEventListener("click", () => {
        const mac = sel.value;
        if (!mac || !devicesMap[mac]) return;
        const n = String((devicesMap[mac].name || "").trim() || mac);
        rows.push({ mac, name: n });
        sel.value = "";
        renderZoneDevicesEditor(containerEl, rows, devicesMap);
    });
    addWrap.appendChild(sel);
    addWrap.appendChild(addBtn);
    containerEl.appendChild(addWrap);
}

/** Default device name list when creating a zone (refined in Edit zone). */
async function defaultDeviceNamesForNewTab() {
    const dm = await fetchDevicesMap();
    const macs = Object.keys(dm);
    if (macs.length > 0) {
        const m0 = macs[0];
        return [String((dm[m0].name || "").trim() || m0)];
    }
    return ["1"];
}

/** Read zone device names from the presets section (JSON attr preferred; legacy comma list fallback). */
function parseTabDeviceNames(section) {
    if (!section) return [];
    const enc = section.getAttribute("data-device-names-json");
    if (enc) {
        try {
            const arr = JSON.parse(decodeURIComponent(enc));
            return Array.isArray(arr) ? arr.map((n) => String(n).trim()).filter((n) => n.length > 0) : [];
        } catch (e) {
            /* ignore */
        }
    }
    const legacy = section.getAttribute("data-device-names");
    if (legacy) {
        return legacy.split(",").map((n) => n.trim()).filter((n) => n.length > 0);
    }
    return [];
}

window.parseTabDeviceNames = parseTabDeviceNames;
window.parseZoneDeviceNames = parseTabDeviceNames;

function escapeHtmlAttr(s) {
    return String(s)
        .replace(/&/g, "&amp;")
        .replace(/"/g, "&quot;")
        .replace(/</g, "&lt;");
}

// Load tabs list
async function loadZones() {
    try {
        const response = await fetch('/zones');
        const data = await response.json();
        
        // Get current zone from cookie first, then from server response
        const cookieTabId = getCurrentZoneFromCookie();
        const serverCurrent = data.current_zone_id;
        const tabs = data.zones || {};
        const zoneIds = Object.keys(tabs);

        let candidateId = cookieTabId || serverCurrent || null;
        // If the candidate doesn't exist anymore (e.g. after DB reset), fall back to first zone.
        if (candidateId && !zoneIds.includes(String(candidateId))) {
            candidateId = zoneIds.length > 0 ? zoneIds[0] : null;
            // Clear stale cookie
            document.cookie = 'current_zone=; path=/; max-age=0';
        }

        currentZoneId = candidateId;
        renderZonesList(data.zones, data.zone_order, currentZoneId);
        
        // Load current zone content if available
        if (currentZoneId) {
            await loadZoneContent(currentZoneId);
        } else if (data.zone_order && data.zone_order.length > 0) {
            // Set first zone as current if none is set
            const firstTabId = data.zone_order[0];
            await setCurrentZone(firstTabId);
            await loadZoneContent(firstTabId);
        }
    } catch (error) {
        console.error('Failed to load zones:', error);
        const container = document.getElementById('zones-list');
        if (container) {
            container.innerHTML = '<div class="error">Failed to load zones</div>';
        }
    }
}

// Render tabs list in the main UI
function renderZonesList(tabs, tabOrder, currentZoneId) {
    const container = document.getElementById('zones-list');
    if (!container) return;
    
    if (!tabOrder || tabOrder.length === 0) {
        container.innerHTML = '<div class="muted-text">No zones available</div>';
        return;
    }
    
    const editMode = isEditModeActive();
    let html = '<div class="zones-list">';
    for (const zoneId of tabOrder) {
        const zone = tabs[zoneId];
        if (zone) {
            const activeClass = zoneId === currentZoneId ? 'active' : '';
            const tabName = zone.name || `Zone ${zoneId}`;
            html += `
                <button class="zone-button ${activeClass}" 
                        data-zone-id="${zoneId}"
                        title="${editMode ? 'Click to select, right-click to edit' : 'Click to select'}"
                        onclick="selectZone('${zoneId}')">
                    ${tabName}
                </button>
            `;
        }
    }
    html += '</div>';
    container.innerHTML = html;
}

// Render tabs list in modal (like profiles)
function renderZonesListModal(tabs, tabOrder, currentZoneId) {
    const container = document.getElementById('zones-list-modal');
    if (!container) return;
    
    container.innerHTML = "";
    let entries = [];

    if (Array.isArray(tabOrder)) {
        entries = tabOrder.map((zoneId) => [zoneId, tabs[zoneId] || {}]);
    } else if (tabs && typeof tabs === "object") {
        entries = Object.entries(tabs).filter(([key]) => {
            return key !== 'current_zone_id' && key !== 'zones' && key !== 'zone_order';
        });
    }

    if (entries.length === 0) {
        const empty = document.createElement("p");
        empty.className = "muted-text";
        empty.textContent = "No zones found.";
        container.appendChild(empty);
        return;
    }

    const editMode = isEditModeActive();
    entries.forEach(([zoneId, zone]) => {
        const row = document.createElement("div");
        row.className = "profiles-row";
        row.dataset.zoneId = String(zoneId);

        const label = document.createElement("span");
        label.textContent = (zone && zone.name) || zoneId;
        if (String(zoneId) === String(currentZoneId)) {
            label.textContent = `✓ ${label.textContent}`;
            label.style.fontWeight = "bold";
            label.style.color = "#FFD700";
        }

        const applyButton = document.createElement("button");
        applyButton.className = "btn btn-secondary btn-small";
        applyButton.textContent = "Select";
        applyButton.addEventListener("click", async () => {
            await selectZone(zoneId);
            document.getElementById('zones-modal').classList.remove('active');
        });

        const editButton = document.createElement("button");
        editButton.className = "btn btn-secondary btn-small";
        editButton.textContent = "Edit";
        editButton.addEventListener("click", async () => {
            await openEditZoneModal(zoneId, zone);
        });

        const cloneButton = document.createElement("button");
        cloneButton.className = "btn btn-secondary btn-small";
        cloneButton.textContent = "Clone";
        cloneButton.addEventListener("click", async () => {
            const baseName = (zone && zone.name) || zoneId;
            const suggested = `${baseName} Copy`;
            const name = prompt("New zone name:", suggested);
            if (name === null) {
                return;
            }
            const trimmed = String(name).trim();
            if (!trimmed) {
                alert("Zone name cannot be empty.");
                return;
            }
            try {
                const response = await fetch(`/zones/${zoneId}/clone`, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        "Accept": "application/json",
                    },
                    body: JSON.stringify({ name: trimmed }),
                });
                if (!response.ok) {
                    const errorData = await response.json().catch(() => ({ error: "Failed to clone zone" }));
                    throw new Error(errorData.error || "Failed to clone zone");
                }
                const data = await response.json().catch(() => null);
                let newTabId = null;
                if (data && typeof data === "object") {
                    if (data.id) {
                        newTabId = String(data.id);
                    } else {
                        const ids = Object.keys(data);
                        if (ids.length > 0) {
                            newTabId = String(ids[0]);
                        }
                    }
                }
                await loadZonesModal();
                if (newTabId) {
                    await selectZone(newTabId);
                } else {
                    await loadZones();
                }
            } catch (error) {
                console.error("Clone zone failed:", error);
                alert("Failed to clone zone: " + error.message);
            }
        });

        const deleteButton = document.createElement("button");
        deleteButton.className = "btn btn-danger btn-small";
        deleteButton.textContent = "Delete";
        deleteButton.addEventListener("click", async () => {
            const confirmed = confirm(`Delete zone "${label.textContent}"?`);
            if (!confirmed) {
                return;
            }
            try {
                const response = await fetch(`/zones/${zoneId}`, {
                    method: "DELETE",
                    headers: { Accept: "application/json" },
                });
                if (!response.ok) {
                    const errorData = await response.json().catch(() => ({ error: "Failed to delete zone" }));
                    throw new Error(errorData.error || "Failed to delete zone");
                }
                // Clear cookie if deleted zone was current
                if (zoneId === currentZoneId) {
                    document.cookie = 'current_zone=; path=/; max-age=0';
                    currentZoneId = null;
                }
                await loadZonesModal();
                await loadZones(); // Reload main tabs list
            } catch (error) {
                console.error("Delete zone failed:", error);
                alert("Failed to delete zone: " + error.message);
            }
        });

        row.appendChild(label);
        row.appendChild(applyButton);
        if (editMode) {
            row.appendChild(editButton);
            row.appendChild(cloneButton);
            row.appendChild(deleteButton);
        }
        container.appendChild(row);
    });
}

// Load tabs in modal
async function loadZonesModal() {
    const container = document.getElementById('zones-list-modal');
    if (!container) return;
    
    container.innerHTML = "";
    const loading = document.createElement("p");
    loading.className = "muted-text";
    loading.textContent = "Loading zones...";
    container.appendChild(loading);

    try {
        const response = await fetch("/zones", {
            headers: { Accept: "application/json" },
        });
        if (!response.ok) {
            throw new Error("Failed to load zones");
        }
        const data = await response.json();
        const tabs = data.zones || data;
        const currentZoneId = getCurrentZoneFromCookie() || data.current_zone_id || null;
        renderZonesListModal(tabs, data.zone_order || [], currentZoneId);
    } catch (error) {
        console.error("Load tabs failed:", error);
        container.innerHTML = "";
        const errorMessage = document.createElement("p");
        errorMessage.className = "muted-text";
        errorMessage.textContent = "Failed to load zones.";
        container.appendChild(errorMessage);
    }
}

// Select a zone
async function selectZone(zoneId) {
    // Update active state
    document.querySelectorAll('.zone-button').forEach(btn => {
        btn.classList.remove('active');
    });
    const btn = document.querySelector(`[data-zone-id="${zoneId}"]`);
    if (btn) {
        btn.classList.add('active');
    }
    
    // Set as current zone
    await setCurrentZone(zoneId);
    // Load zone content
    loadZoneContent(zoneId);
}

// Set current zone in cookie
async function setCurrentZone(zoneId) {
    try {
        const response = await fetch(`/zones/${zoneId}/set-current`, {
            method: 'POST'
        });
        const data = await response.json();
        if (response.ok) {
            currentZoneId = zoneId;
            // Also set cookie on client side
            document.cookie = `current_zone=${zoneId}; path=/; max-age=31536000`;
        } else {
            console.error('Failed to set current zone:', data.error);
        }
    } catch (error) {
        console.error('Error setting current zone:', error);
    }
}

// Load zone content
async function loadZoneContent(zoneId) {
    const container = document.getElementById('zone-content');
    if (!container) return;
    
    try {
        const response = await fetch(`/zones/${zoneId}`);
        const zone = await response.json();
        
        if (zone.error) {
            container.innerHTML = `<div class="error">${zone.error}</div>`;
            return;
        }
        
        // Render zone content (presets section)
        const tabName = zone.name || `Zone ${zoneId}`;
        const names = Array.isArray(zone.names) ? zone.names : [];
        const namesJsonAttr = encodeURIComponent(JSON.stringify(names));
        const legacyOk = names.length > 0 && !names.some((n) => /[",]/.test(String(n)));
        const legacyAttr = legacyOk ? ` data-device-names="${escapeHtmlAttr(names.join(","))}"` : "";
        container.innerHTML = `
            <div class="presets-section" data-zone-id="${zoneId}" data-device-names-json="${namesJsonAttr}"${legacyAttr}>
                <div id="presets-list-zone" class="presets-list">
                    <!-- Presets will be loaded here by presets.js -->
                </div>
            </div>
        `;

        // Keep header and menu brightness controls in sync.
        const zoneBrightness =
            typeof zone.brightness === 'number'
                ? zone.brightness
                : parseInt(String(zone.brightness ?? ''), 10);
        const normalizedBrightness = Number.isFinite(zoneBrightness)
            ? Math.max(0, Math.min(255, Math.round(zoneBrightness)))
            : 255;
        applyBrightnessSliders(normalizedBrightness);
        // Apply this zone's saved brightness when switching zones.
        sendZoneBrightness(zoneId, normalizedBrightness);
        
        // Trigger presets loading if the function exists
        if (typeof renderTabPresets === 'function') {
            renderTabPresets(zoneId);
        }
    } catch (error) {
        console.error('Failed to load zone content:', error);
        container.innerHTML = '<div class="error">Failed to load zone content</div>';
    }
}

// Send all presets used by all tabs in the current profile via /presets/send.
async function sendProfilePresets() {
    try {
        // Load current profile to get its tabs
        const profileRes = await fetch('/profiles/current', {
            headers: { Accept: 'application/json' },
        });
        if (!profileRes.ok) {
            alert('Failed to load current profile.');
            return;
        }
        const profileData = await profileRes.json();
        const profile = profileData.profile || {};
        let zoneList = null;
        if (Array.isArray(profile.zones)) {
            zoneList = profile.zones;
        } else if (profile.zones) {
            zoneList = [profile.zones];
        }
        if (!zoneList || zoneList.length === 0) {
            if (Array.isArray(profile.zones)) {
                zoneList = profile.zones;
            } else if (profile.zones) {
                zoneList = [profile.zones];
            }
        }
        if (!zoneList || zoneList.length === 0) {
            console.warn('sendProfilePresets: no zones found', {
                profileData,
                profile,
            });
        }

        if (!zoneList.length) {
            alert('Current profile has no zones to send presets for.');
            return;
        }

        let totalSent = 0;
        let totalMessages = 0;
        let zonesWithPresets = 0;

        for (const zoneId of zoneList) {
            try {
                const tabResp = await fetch(`/zones/${zoneId}`, {
                    headers: { Accept: 'application/json' },
                });
                if (!tabResp.ok) {
                    continue;
                }
                const tabData = await tabResp.json();
                let presetIds = [];
                if (Array.isArray(tabData.presets_flat)) {
                    presetIds = tabData.presets_flat;
                } else if (Array.isArray(tabData.presets)) {
                    if (tabData.presets.length && typeof tabData.presets[0] === 'string') {
                        presetIds = tabData.presets;
                    } else if (tabData.presets.length && Array.isArray(tabData.presets[0])) {
                        presetIds = tabData.presets.flat();
                    }
                }
                presetIds = (presetIds || []).filter(Boolean);
                if (!presetIds.length) {
                    continue;
                }
                zonesWithPresets += 1;
                const zoneNames = Array.isArray(tabData.names) ? tabData.names : [];
                const targets = await resolveZoneDeviceMacs(zoneNames);
                const payload = { preset_ids: presetIds };
                if (tabData.default_preset) {
                    payload.default = tabData.default_preset;
                }
                if (targets.length > 0) {
                    payload.targets = targets;
                }
                const response = await fetch('/presets/send', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Accept': 'application/json',
                    },
                    body: JSON.stringify(payload),
                });
                const data = await response.json().catch(() => ({}));
                if (!response.ok) {
                    const msg = (data && data.error) || `Failed to send presets for zone ${zoneId}.`;
                    console.warn(msg);
                    continue;
                }
                totalSent += typeof data.presets_sent === 'number' ? data.presets_sent : presetIds.length;
                totalMessages += typeof data.messages_sent === 'number' ? data.messages_sent : 0;
            } catch (e) {
                console.error('Failed to send profile presets for zone:', zoneId, e);
            }
        }

        if (!zonesWithPresets) {
            alert('No presets to send for the current profile.');
            return;
        }

        const messagesLabel = totalMessages ? totalMessages : '?';
        alert(`Sent ${totalSent} preset(s) across ${zonesWithPresets} zone(s) (${messagesLabel} driver send(s)).`);
    } catch (error) {
        console.error('Failed to send profile presets:', error);
        alert('Failed to send profile presets.');
    }
}

function tabPresetIdsInOrder(tabData) {
    let ids = [];
    if (Array.isArray(tabData.presets_flat)) {
        ids = tabData.presets_flat.slice();
    } else if (Array.isArray(tabData.presets)) {
        if (tabData.presets.length && typeof tabData.presets[0] === "string") {
            ids = tabData.presets.slice();
        } else if (tabData.presets.length && Array.isArray(tabData.presets[0])) {
            ids = tabData.presets.flat();
        }
    }
    return (ids || []).filter(Boolean);
}

// Presets already on the zone (remove) and presets available to add (select).
async function refreshEditTabPresetsUi(zoneId) {
    const currentEl = document.getElementById("edit-zone-presets-current");
    const addEl = document.getElementById("edit-zone-presets-list");
    if (!zoneId || !currentEl || !addEl) return;

    currentEl.innerHTML = '<span class="muted-text">Loading…</span>';
    addEl.innerHTML = '<span class="muted-text">Loading…</span>';

    try {
        const tabRes = await fetch(`/zones/${zoneId}`, { headers: { Accept: "application/json" } });
        if (!tabRes.ok) {
            const msg = '<span class="muted-text">Failed to load zone presets.</span>';
            currentEl.innerHTML = msg;
            addEl.innerHTML = msg;
            return;
        }
        const tabData = await tabRes.json();
        const inTabIds = tabPresetIdsInOrder(tabData);
        const inTabSet = new Set(inTabIds.map((id) => String(id)));

        const presetsRes = await fetch("/presets", { headers: { Accept: "application/json" } });
        const allPresets = presetsRes.ok ? await presetsRes.json() : {};

        const makeRow = () => {
            const row = document.createElement("div");
            row.className = "profiles-row";
            row.style.display = "flex";
            row.style.alignItems = "center";
            row.style.justifyContent = "space-between";
            row.style.gap = "0.5rem";
            return row;
        };

        currentEl.innerHTML = "";
        if (inTabIds.length === 0) {
            currentEl.innerHTML = '<span class="muted-text">No presets on this zone yet.</span>';
        } else {
            for (const presetId of inTabIds) {
                const preset = allPresets[presetId] || {};
                const name = preset.name || presetId;
                const row = makeRow();
                const label = document.createElement("span");
                label.textContent = name;
                const removeBtn = document.createElement("button");
                removeBtn.type = "button";
                removeBtn.className = "btn btn-danger btn-small";
                removeBtn.textContent = "Remove";
                removeBtn.addEventListener("click", async () => {
                    if (typeof window.removePresetFromTab !== "function") return;
                    if (!window.confirm(`Remove this preset from the zone?\n\n${name}`)) return;
                    await window.removePresetFromTab(zoneId, presetId);
                    await refreshEditTabPresetsUi(zoneId);
                });
                row.appendChild(label);
                row.appendChild(removeBtn);
                currentEl.appendChild(row);
            }
        }

        const allIds = Object.keys(allPresets);
        const availableToAdd = allIds.filter((id) => !inTabSet.has(String(id)));
        addEl.innerHTML = "";
        if (availableToAdd.length === 0) {
            addEl.innerHTML =
                '<span class="muted-text">No presets to add. All presets are already on this zone.</span>';
        } else {
            const addWrap = document.createElement("div");
            addWrap.className = "zone-devices-add profiles-actions";
            const sel = document.createElement("select");
            sel.className = "zone-device-add-select";
            sel.setAttribute("aria-label", "Preset to add to this zone");
            sel.appendChild(new Option("Add preset…", ""));
            const sorted = availableToAdd.slice().sort((a, b) => {
                const na = (allPresets[a] && allPresets[a].name) || a;
                const nb = (allPresets[b] && allPresets[b].name) || b;
                return String(na).localeCompare(String(nb), undefined, { sensitivity: "base" });
            });
            sorted.forEach((presetId) => {
                const preset = allPresets[presetId] || {};
                const name = preset.name || presetId;
                sel.appendChild(new Option(`${name} — ${presetId}`, presetId));
            });
            const addBtn = document.createElement("button");
            addBtn.type = "button";
            addBtn.className = "btn btn-primary btn-small";
            addBtn.textContent = "Add";
            addBtn.addEventListener("click", async () => {
                const presetId = sel.value;
                if (!presetId) return;
                if (typeof window.addPresetToTab === "function") {
                    await window.addPresetToTab(presetId, zoneId);
                    sel.value = "";
                    await refreshEditTabPresetsUi(zoneId);
                }
            });
            addWrap.appendChild(sel);
            addWrap.appendChild(addBtn);
            addEl.appendChild(addWrap);
        }
    } catch (e) {
        console.error("refreshEditTabPresetsUi:", e);
        const msg = '<span class="muted-text">Failed to load presets.</span>';
        currentEl.innerHTML = msg;
        addEl.innerHTML = msg;
    }
}

async function populateEditTabPresetsList(zoneId) {
    await refreshEditTabPresetsUi(zoneId);
}

// Open edit zone modal
async function openEditZoneModal(zoneId, zone) {
    const modal = document.getElementById("edit-zone-modal");
    const idInput = document.getElementById("edit-zone-id");
    const nameInput = document.getElementById("edit-zone-name");
    const editor = document.getElementById("edit-zone-devices-editor");

    let tabData = zone;
    if (!tabData || typeof tabData !== "object" || tabData.error) {
        try {
            const response = await fetch(`/zones/${zoneId}`);
            if (response.ok) {
                tabData = await response.json();
            }
        } catch (e) {
            console.error("openEditZoneModal fetch zone:", e);
        }
    }
    tabData = tabData || {};

    if (idInput) idInput.value = zoneId;
    if (nameInput) nameInput.value = tabData.name || "";

    const devicesMap = await fetchDevicesMap();
    const zoneNames =
        Array.isArray(tabData.names) && tabData.names.length > 0 ? tabData.names : ["1"];
    window.__editTabDeviceRows = namesToRows(zoneNames, devicesMap);
    renderZoneDevicesEditor(editor, window.__editTabDeviceRows, devicesMap);

    if (modal) modal.classList.add("active");
    await refreshEditTabPresetsUi(zoneId);
}

function normalizeTabNamesArg(namesOrString) {
    if (Array.isArray(namesOrString)) {
        return namesOrString.map((n) => String(n).trim()).filter((n) => n.length > 0);
    }
    if (typeof namesOrString === "string" && namesOrString.trim()) {
        return namesOrString.split(",").map((id) => id.trim()).filter((id) => id.length > 0);
    }
    return ["1"];
}

// Update an existing zone
async function updateZone(zoneId, name, namesOrString) {
    try {
        let names = normalizeTabNamesArg(namesOrString);
        if (!names.length) names = ["1"];
        const response = await fetch(`/zones/${zoneId}`, {
            method: 'PUT',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                name: name,
                names: names
            })
        });
        
        const data = await response.json();
        if (response.ok) {
            // Reload tabs list
            await loadZonesModal();
            await loadZones();
            // Close modal
            document.getElementById('edit-zone-modal').classList.remove('active');
            return true;
        } else {
            alert(`Error: ${data.error || 'Failed to update zone'}`);
            return false;
        }
    } catch (error) {
        console.error('Failed to update zone:', error);
        alert('Failed to update zone');
        return false;
    }
}

// Create a new zone
async function createZone(name, namesOrString) {
    try {
        let names = normalizeTabNamesArg(namesOrString);
        if (!names.length) names = ["1"];
        const response = await fetch('/zones', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                name: name,
                names: names
            })
        });
        
        const data = await response.json();
        if (response.ok) {
            // Reload tabs list
            await loadZonesModal();
            await loadZones();
            // Select the new zone
            if (data && Object.keys(data).length > 0) {
                const newTabId = Object.keys(data)[0];
                await selectZone(newTabId);
            }
            return true;
        } else {
            alert(`Error: ${data.error || 'Failed to create zone'}`);
            return false;
        }
    } catch (error) {
        console.error('Failed to create zone:', error);
        alert('Failed to create zone');
        return false;
    }
}

// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
    loadZones();
    
    // Set up tabs modal
    const tabsButton = document.getElementById('zones-btn');
    const zonesModal = document.getElementById('zones-modal');
    const tabsCloseButton = document.getElementById('zones-close-btn');
    const newTabNameInput = document.getElementById("new-zone-name");
    const createZoneButton = document.getElementById("create-zone-btn");

    if (tabsButton && zonesModal) {
        tabsButton.addEventListener("click", async () => {
            zonesModal.classList.add("active");
            await loadZonesModal();
        });
    }
    
    if (tabsCloseButton) {
        tabsCloseButton.addEventListener('click', () => {
            zonesModal.classList.remove('active');
        });
    }
    
    // Right-click on a zone button in the main header bar to edit that zone
    document.addEventListener('contextmenu', async (event) => {
        if (!isEditModeActive()) {
            return;
        }
        const btn = event.target.closest('.zone-button');
        if (!btn || !btn.dataset.zoneId) {
            return;
        }
        event.preventDefault();
        const zoneId = btn.dataset.zoneId;
        try {
            const response = await fetch(`/zones/${zoneId}`);
            if (response.ok) {
                const zone = await response.json();
                await openEditZoneModal(zoneId, zone);
            } else {
                alert('Failed to load zone for editing');
            }
        } catch (error) {
            console.error('Failed to load zone:', error);
            alert('Failed to load zone for editing');
        }
    });
    
    // Set up create zone
    const createZoneHandler = async () => {
        if (!newTabNameInput) return;
        const name = newTabNameInput.value.trim();

        if (name) {
            const deviceNames = await defaultDeviceNamesForNewTab();
            await createZone(name, deviceNames);
            if (newTabNameInput) newTabNameInput.value = "";
        }
    };
    
    if (createZoneButton) {
        createZoneButton.addEventListener('click', createZoneHandler);
    }
    
    if (newTabNameInput) {
        newTabNameInput.addEventListener('keypress', (event) => {
            if (event.key === 'Enter') {
                createZoneHandler();
            }
        });
    }
    
    // Set up edit zone form
    const editZoneForm = document.getElementById('edit-zone-form');
    if (editZoneForm) {
        editZoneForm.addEventListener("submit", async (e) => {
            e.preventDefault();
            const idInput = document.getElementById("edit-zone-id");
            const nameInput = document.getElementById("edit-zone-name");

            const zoneId = idInput ? idInput.value : null;
            const name = nameInput ? nameInput.value.trim() : "";
            const rows = window.__editTabDeviceRows || [];
            const deviceNames = rowsToNames(rows);

            if (zoneId && name) {
                if (deviceNames.length === 0) {
                    alert("Add at least one device.");
                    return;
                }
                await updateZone(zoneId, name, deviceNames);
                editZoneForm.reset();
            }
        });
    }
    
    // Profile-wide "Send Presets" button in header
    const sendProfilePresetsBtn = document.getElementById('send-profile-presets-btn');
    if (sendProfilePresetsBtn) {
        sendProfilePresetsBtn.addEventListener('click', async () => {
            await sendProfilePresets();
        });
    }

    const menuBrightnessSlider = document.getElementById('menu-brightness-slider');
    const headerBrightnessSlider = document.getElementById('header-brightness-slider');
    (async () => {
        if (menuBrightnessSlider) {
            menuBrightnessSlider.addEventListener('input', (e) => {
                if (!currentZoneId) return;
                sendZoneBrightness(currentZoneId, e.target.value);
            });
        }
        if (headerBrightnessSlider) {
            headerBrightnessSlider.addEventListener('input', (e) => {
                if (!currentZoneId) return;
                sendZoneBrightness(currentZoneId, e.target.value);
            });
        }
    })();

    // When run/edit mode toggles, refresh tabs UI so edit actions show/hide immediately.
    document.querySelectorAll('.ui-mode-toggle').forEach((btn) => {
        btn.addEventListener('click', async () => {
            await loadZones();
            if (zonesModal && zonesModal.classList.contains("active")) {
                await loadZonesModal();
            }
        });
    });
});

// Export for use in other scripts
window.zonesManager = {
    loadZones,
    loadZonesModal,
    selectZone,
    createZone,
    updateZone,
    openEditZoneModal,
    resolveZoneDeviceMacs,
    resolveTabDeviceMacs: resolveZoneDeviceMacs,
    getCurrentZoneId: () => currentZoneId,
};
window.tabsManager = window.zonesManager;
window.tabsManager.getCurrentTabId = () => currentZoneId;
window.tabsManager.loadTabs = loadZones;
window.tabsManager.loadTabsModal = loadZonesModal;
window.tabsManager.openEditTabModal = openEditZoneModal;
