// Lighting Controller Web App
class LightingController {
    constructor() {
        this.currentTab = null;
        this.state = {
            lights: {},
            patterns: {},
            zone_order: [],
            presets: {}
        };
        this.selectedColorIndex = 0;
        this.updateTimeouts = {};
        this.quickPaletteContext = null;
        
        this.init();
    }

    async init() {
        await this.loadState();
        this.setupEventListeners();
        this.renderTabs();
        if (this.state.zone_order.length > 0) {
            this.selectTab(this.state.zone_order[0]);
        }
    }

    async loadState() {
        try {
            // Load presets and profiles separately since /api/state doesn't exist
            const presetsResponse = await fetch('/presets');
            const presets = await presetsResponse.json();
            this.state.presets = presets || {};
            
            const patternsResponse = await fetch('/patterns');
            if (patternsResponse.ok) {
                const patterns = await patternsResponse.json();
                this.state.patterns = patterns || {};
            }
            
            // Load profiles
            const profilesResponse = await fetch('/profiles');
            const profiles = await profilesResponse.json();
            
            // Update current profile display
            this.updateCurrentProfileDisplay();
            // Update current profile display if profiles modal is open
            if (document.getElementById('profiles-modal').classList.contains('active')) {
                await this.loadProfiles();
                await this.loadProfilePalette();
            }
        } catch (error) {
            console.error('Failed to load state:', error);
        }
    }

    updateCurrentProfileDisplay() {
        const currentProfileName = document.getElementById('current-profile-name');
        if (currentProfileName) {
            const profile = this.state.current_profile || 'None';
            currentProfileName.textContent = profile;
        }
    }

    setupEventListeners() {
        // Zone management
        document.getElementById('add-zone-btn').addEventListener('click', () => this.showAddTabModal());
        document.getElementById('edit-zone-btn').addEventListener('click', () => this.showEditTabModal());
        document.getElementById('delete-zone-btn').addEventListener('click', () => this.deleteCurrentTab());
        document.getElementById('color-palette-btn').addEventListener('click', () => this.showColorPalette());
        document.getElementById('presets-btn').addEventListener('click', () => this.showPresets());
        document.getElementById('profiles-btn').addEventListener('click', () => this.showProfiles());

        // Modal actions
        document.getElementById('add-zone-confirm').addEventListener('click', () => this.createTab());
        document.getElementById('add-zone-cancel').addEventListener('click', () => this.hideModal('add-zone-modal'));
        document.getElementById('edit-zone-confirm').addEventListener('click', () => this.updateTab());
        document.getElementById('edit-zone-cancel').addEventListener('click', () => this.hideModal('edit-zone-modal'));
        document.getElementById('profiles-close-btn').addEventListener('click', () => this.hideModal('profiles-modal'));
        document.getElementById('color-palette-close-btn').addEventListener('click', () => this.hideModal('color-palette-modal'));
        document.getElementById('presets-close-btn').addEventListener('click', () => this.hideModal('presets-modal'));
        document.getElementById('create-preset-btn').addEventListener('click', () => this.showPresetEditor());
        document.getElementById('preset-editor-save-btn').addEventListener('click', () => this.savePreset());
        document.getElementById('preset-editor-cancel-btn').addEventListener('click', () => this.hideModal('preset-editor-modal'));
        document.getElementById('preset-add-color-btn').addEventListener('click', () => this.addPresetColor());
        document.getElementById('preset-remove-color-btn').addEventListener('click', () => this.removePresetColor());
        document.getElementById('preset-editor-from-current-btn').addEventListener('click', () => this.loadCurrentTabToPresetEditor());
        document.getElementById('preset-brightness-slider').addEventListener('input', (e) => {
            document.getElementById('preset-brightness-value').textContent = e.target.value;
        });
        document.getElementById('quick-palette-close-btn').addEventListener('click', () => this.hideQuickPaletteModal());
        document.getElementById('quick-palette-use-picker-btn').addEventListener('click', () => this.useColorPickerFromQuickPalette());
        document.getElementById('create-profile-btn').addEventListener('click', () => this.createProfile());
        document.getElementById('add-palette-color-btn').addEventListener('click', () => this.addPaletteColor());
        document.getElementById('palette-add-color-btn').addEventListener('click', () => this.addPaletteColorFromModal());
        document.getElementById('toggle-left-panel').addEventListener('click', () => this.toggleLeftPanel());
        
        // Enter key for new profile name
        document.getElementById('new-profile-name').addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                this.createProfile();
            }
        });

        // Brightness and delay sliders
        document.getElementById('brightness-slider').addEventListener('input', (e) => {
            document.getElementById('brightness-value').textContent = e.target.value;
            this.debounceUpdate('brightness', () => this.updateBrightness());
        });
        document.getElementById('delay-slider').addEventListener('input', (e) => {
            this.updateDelayValue(e.target.value);
            this.debounceUpdate('delay', () => this.updateDelay());
        });

        // N parameters
        for (let i = 1; i <= 8; i++) {
            document.getElementById(`n${i}-input`).addEventListener('input', (e) => {
                this.debounceUpdate('nparams', () => this.updateNParams());
            });
        }

        // Color palette
        document.getElementById('add-color-btn').addEventListener('click', () => this.addColorToPalette());
        document.getElementById('remove-color-btn').addEventListener('click', () => this.removeSelectedColor());

    }

    renderTabs() {
        const tabsList = document.getElementById('zones-list');
        tabsList.innerHTML = '';
        
        this.state.zone_order.forEach(tabName => {
            const tabButton = document.createElement('button');
            tabButton.className = 'zone-button';
            tabButton.textContent = tabName;
            tabButton.addEventListener('click', () => this.selectTab(tabName));
            if (tabName === this.currentTab) {
                tabButton.classList.add('active');
            }
            tabsList.appendChild(tabButton);
        });
    }

    toggleLeftPanel() {
        const leftPanel = document.querySelector('.left-panel');
        if (!leftPanel) return;
        leftPanel.classList.toggle('collapsed');
    }

    async selectTab(tabName) {
        if (!this.state.lights[tabName]) return;
        
        this.currentTab = tabName;
        this.renderTabs();
        await this.loadTabContent(tabName);
    }

    async loadTabContent(tabName) {
        const light = this.state.lights[tabName];
        if (!light) {
            return;
        }
        const settings = light.settings;
        const pattern = settings.pattern || 'on';
        
        // Get pattern-specific settings
        const patternSettings = this.getPatternSettings(tabName, pattern);
        
        // Update IDs display
        document.getElementById('current-ids').textContent = light.names.join(', ');
        
        // Load and render colors in the palette
        const colors = patternSettings.colors || ['#000000'];
        this.renderColorPalette(tabName, colors);
        
        // Update brightness slider
        const brightness = settings.brightness || 127;
        document.getElementById('brightness-slider').value = brightness;
        document.getElementById('brightness-value').textContent = brightness;
        
        // Update delay slider
        const patternConfig = this.state.patterns[pattern] || {};
        const minDelay = patternConfig.min_delay || 10;
        const maxDelay = patternConfig.max_delay || 10000;
        const delaySliderPos = this.delayToSlider(patternSettings.delay, minDelay, maxDelay);
        document.getElementById('delay-slider').value = delaySliderPos;
        this.updateDelayValue(delaySliderPos, minDelay, maxDelay);
        
        // Update n parameters
        for (let i = 1; i <= 8; i++) {
            document.getElementById(`n${i}-input`).value = patternSettings[`n${i}`] || 10;
        }
        this.updateNParamLabels(pattern);
        
        // Render presets
        this.renderPresets(tabName);
    }

    updateNParamLabels(patternName) {
        const defaultLabels = {};
        for (let i = 1; i <= 8; i++) {
            defaultLabels[`n${i}`] = `n${i}:`;
        }
        const patternConfig = this.state.patterns ? this.state.patterns[patternName] : null;
        if (patternConfig && typeof patternConfig === 'object') {
            Object.entries(patternConfig).forEach(([label, key]) => {
                if (typeof key === 'string' && key.startsWith('n')) {
                    defaultLabels[key] = `${label}:`;
                }
            });
        }
        for (let i = 1; i <= 8; i++) {
            const labelEl = document.getElementById(`n${i}-label`);
            if (labelEl) {
                labelEl.textContent = defaultLabels[`n${i}`];
            }
        }
    }

    renderPresets(tabName) {
        const presetsList = document.getElementById('presets-list-zone');
        presetsList.innerHTML = '';
        
        const presets = this.state.presets || {};
        const presetNames = Object.keys(presets);
        
        // Get current zone's settings for comparison
        const currentSettings = this.getCurrentTabSettings(tabName);
        
        // Always include "on" and "off" presets
        const defaultPresets = {
            'on': {
                pattern: 'on',
                colors: ['#FFFFFF'],
                brightness: 255,
                delay: 100,
                n1: 10,
                n2: 10,
                n3: 10,
                n4: 10,
                n5: 10,
                n6: 10,
                n7: 10,
                n8: 10
            },
            'off': {
                pattern: 'off',
                colors: ['#000000'],
                brightness: 0,
                delay: 100,
                n1: 10,
                n2: 10,
                n3: 10,
                n4: 10,
                n5: 10,
                n6: 10,
                n7: 10,
                n8: 10
            }
        };
        
        // Create a combined list with default presets first, then user presets
        const allPresets = { ...defaultPresets, ...presets };
        const allPresetNames = ['on', 'off', ...presetNames.filter(name => name !== 'on' && name !== 'off')];
        
        allPresetNames.forEach(presetName => {
            const preset = allPresets[presetName];
            const presetButton = document.createElement('button');
            presetButton.className = 'pattern-button';
            
            // Check if this preset matches the current zone's settings
            const isActive = this.presetMatchesSettings(preset, currentSettings);
            if (isActive) {
                presetButton.classList.add('active');
            }
            
            // Mark default presets (on/off) with a special indicator
            const isDefault = presetName === 'on' || presetName === 'off';
            if (isDefault) {
                presetButton.classList.add('default-preset');
            }
            
            // Create preset info display
            const presetInfo = document.createElement('div');
            presetInfo.style.cssText = 'display: flex; flex-direction: column; align-items: flex-start; width: 100%;';
            
            const presetNameLabel = document.createElement('span');
            presetNameLabel.textContent = presetName;
            presetNameLabel.style.fontWeight = 'bold';
            presetNameLabel.style.marginBottom = '0.25rem';
            
            const presetDetails = document.createElement('span');
            presetDetails.style.fontSize = '0.85em';
            presetDetails.style.color = '#aaa';
            presetDetails.textContent = `${preset.pattern} • ${preset.colors.length} color${preset.colors.length !== 1 ? 's' : ''}`;
            
            presetInfo.appendChild(presetNameLabel);
            presetInfo.appendChild(presetDetails);
            presetButton.appendChild(presetInfo);
            
            presetButton.addEventListener('click', () => {
                if (isDefault && !presets[presetName]) {
                    // Apply default preset directly
                    this.applyDefaultPreset(tabName, presetName, preset);
                } else {
                    // Apply regular preset
                    this.applyPresetToTab(tabName, presetName);
                }
            });
            presetsList.appendChild(presetButton);
        });
    }
    
    async applyDefaultPreset(tabName, presetName, preset) {
        // Apply default preset by setting pattern and parameters directly
        try {
            // First set the pattern
            const patternResponse = await fetch('/api/pattern', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: tabName,
                    pattern: preset.pattern,
                    delay: preset.delay,
                    colors: preset.colors,
                    n1: preset.n1,
                    n2: preset.n2,
                    n3: preset.n3,
                    n4: preset.n4,
                    n5: preset.n5,
                    n6: preset.n6,
                    n7: preset.n7,
                    n8: preset.n8
                })
            });
            
            if (patternResponse.ok) {
                // Then update brightness
                await fetch('/api/parameters', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({
                        tab_name: tabName,
                        brightness: preset.brightness
                    })
                });
                
                // Reload state and zone content
                await this.loadState();
                await this.loadTabContent(tabName);
            } else {
                const error = await patternResponse.json();
                alert(`Failed to apply preset: ${error.error || 'Unknown error'}`);
            }
        } catch (error) {
            console.error('Failed to apply default preset:', error);
            alert('Failed to apply preset');
        }
    }
    
    getCurrentTabSettings(tabName) {
        if (!this.state.lights[tabName]) {
            return null;
        }
        
        const light = this.state.lights[tabName];
        const settings = light.settings;
        const pattern = settings.pattern || 'on';
        const patternSettings = this.getPatternSettings(tabName, pattern);
        
        return {
            pattern: pattern,
            brightness: settings.brightness || 127,
            delay: patternSettings.delay || 100,
            colors: patternSettings.colors || ['#000000'],
            n1: patternSettings.n1 || 10,
            n2: patternSettings.n2 || 10,
            n3: patternSettings.n3 || 10,
            n4: patternSettings.n4 || 10,
            n5: patternSettings.n5 || 10,
            n6: patternSettings.n6 || 10,
            n7: patternSettings.n7 || 10,
            n8: patternSettings.n8 || 10
        };
    }
    
    presetMatchesSettings(preset, currentSettings) {
        if (!currentSettings) {
            return false;
        }
        
        // Compare all settings
        if (preset.pattern !== currentSettings.pattern) {
            return false;
        }
        
        if (preset.brightness !== currentSettings.brightness) {
            return false;
        }
        
        if (preset.delay !== currentSettings.delay) {
            return false;
        }
        
        // Compare n values
        for (let i = 1; i <= 8; i++) {
            if (preset[`n${i}`] !== currentSettings[`n${i}`]) {
                return false;
            }
        }
        
        // Compare colors (order matters for presets)
        if (preset.colors.length !== currentSettings.colors.length) {
            return false;
        }
        
        for (let i = 0; i < preset.colors.length; i++) {
            // Normalize color format (uppercase, no spaces)
            const presetColor = preset.colors[i].toUpperCase().trim();
            const currentColor = currentSettings.colors[i].toUpperCase().trim();
            if (presetColor !== currentColor) {
                return false;
            }
        }
        
        return true;
    }
    
    async applyPresetToTab(tabName, presetName) {
        try {
            const preset = this.state.presets[presetName];
            if (!preset) {
                alert('Preset not found');
                return;
            }
            
            // Apply preset using the apply endpoint
            const response = await fetch(`/api/presets/${presetName}/apply`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    tab_name: tabName
                })
            });
            
            if (response.ok) {
                await this.loadState();
                await this.loadTabContent(tabName);
            } else {
                const error = await response.json();
                alert(`Failed to apply preset: ${error.error || 'Unknown error'}`);
            }
        } catch (error) {
            console.error('Failed to apply preset:', error);
            alert('Failed to apply preset');
        }
    }

    renderColorPalette(tabName, colors) {
        const palette = document.getElementById('color-palette');
        if (!palette) {
            return;
        }
        palette.innerHTML = '';
        
        colors.forEach((hexColor, index) => {
            const swatch = document.createElement('div');
            swatch.className = 'color-swatch';
            if (index === this.selectedColorIndex) {
                swatch.classList.add('selected');
            }
            
            const preview = document.createElement('div');
            preview.className = 'color-swatch-preview';
            preview.style.backgroundColor = hexColor;
            
            const label = document.createElement('span');
            label.className = 'color-swatch-label';
            label.textContent = `Color ${index + 1}`;
            
            // Color picker input with palette quick-select
            const colorPickerWrapper = document.createElement('div');
            colorPickerWrapper.style.cssText = 'position: relative; display: inline-block;';
            
            const colorPicker = document.createElement('input');
            colorPicker.type = 'color';
            colorPicker.value = hexColor;
            colorPicker.className = 'color-picker-input';
            colorPicker.dataset.tabName = tabName;
            colorPicker.dataset.colorIndex = index;
            colorPicker.addEventListener('change', (e) => {
                const newColor = e.target.value;
                this.updateColorInPalette(tabName, index, newColor);
            });
            
            // Show quick palette on click, prevent native picker if palette has colors
            const clickHandler = (e) => {
                e.stopPropagation();
                const palette = this.state.color_palette || [];
                // Check if we're allowing native picker (set by "Use Color Picker" button)
                if (palette.length > 0 && !colorPicker.dataset.allowNative) {
                    e.preventDefault();
                    this.showPaletteQuickSelect(colorPickerWrapper, tabName, index, colorPicker);
                }
                // If no palette colors or allowNative is set, let native picker open
            };
            colorPicker.addEventListener('click', clickHandler);
            // Store handler reference for later removal if needed
            colorPicker._clickHandler = clickHandler;
            
            colorPickerWrapper.appendChild(colorPicker);
            
            swatch.appendChild(preview);
            swatch.appendChild(label);
            swatch.appendChild(colorPickerWrapper);
            swatch.addEventListener('click', (e) => {
                // Don't trigger selection if clicking on the color picker
                if (e.target !== colorPicker && !colorPicker.contains(e.target)) {
                    this.selectColor(tabName, index, hexColor);
                }
            });
            
            palette.appendChild(swatch);
        });
    }

    getPatternSettings(tabName, patternName) {
        const light = this.state.lights[tabName];
        if (!light) return {
            colors: ['#000000'],
            delay: 100,
            n1: 10,
            n2: 10,
            n3: 10,
            n4: 10,
            n5: 10,
            n6: 10,
            n7: 10,
            n8: 10
        };
        
        const lightSettings = light.settings;
        if (!lightSettings.patterns) lightSettings.patterns = {};
        if (!lightSettings.patterns[patternName]) lightSettings.patterns[patternName] = {};
        
        const patternSettings = lightSettings.patterns[patternName];
        // Fall back to global colors if pattern-specific colors don't exist
        const globalColors = lightSettings.colors || ['#000000'];
        return {
            colors: patternSettings.colors || globalColors,
            delay: patternSettings.delay || lightSettings.delay || 100,
            n1: patternSettings.n1 || lightSettings.n1 || 10,
            n2: patternSettings.n2 || lightSettings.n2 || 10,
            n3: patternSettings.n3 || lightSettings.n3 || 10,
            n4: patternSettings.n4 || lightSettings.n4 || 10,
            n5: patternSettings.n5 || lightSettings.n5 || 10,
            n6: patternSettings.n6 || lightSettings.n6 || 10,
            n7: patternSettings.n7 || lightSettings.n7 || 10,
            n8: patternSettings.n8 || lightSettings.n8 || 10
        };
    }

    async setPattern(tabName, patternName) {
        const patternSettings = this.getPatternSettings(tabName, patternName);
        
        try {
            const response = await fetch('/api/pattern', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: tabName,
                    pattern: patternName,
                    delay: patternSettings.delay,
                    colors: patternSettings.colors,
                    n1: patternSettings.n1,
                    n2: patternSettings.n2,
                    n3: patternSettings.n3,
                    n4: patternSettings.n4,
                    n5: patternSettings.n5,
                    n6: patternSettings.n6,
                    n7: patternSettings.n7,
                    n8: patternSettings.n8
                })
            });
            
            if (response.ok) {
                // Update the pattern immediately in the state
                if (this.state.lights[tabName]) {
                    this.state.lights[tabName].settings.pattern = patternName;
                }
                // Reload state from server to ensure consistency
                await this.loadState();
                // Reload zone content to update UI
                await this.loadTabContent(tabName);
            } else {
                const errorText = await response.text();
                console.error('Failed to set pattern:', errorText);
                alert(`Failed to set pattern: ${errorText}`);
            }
        } catch (error) {
            console.error('Failed to set pattern:', error);
        }
    }

    selectColor(tabName, index, hexColor) {
        this.selectedColorIndex = index;
        if (this.state.lights[tabName]) {
            const pattern = this.state.lights[tabName].settings.pattern;
            const patternSettings = this.getPatternSettings(tabName, pattern);
            this.renderColorPalette(tabName, patternSettings.colors);
        }
    }

    async updateColorInPalette(tabName, index, hexColor) {
        if (!this.currentTab || tabName !== this.currentTab) return;
        
        const pattern = this.state.lights[tabName].settings.pattern;
        const patternSettings = this.getPatternSettings(tabName, pattern);
        patternSettings.colors[index] = hexColor;
        
        // Update the preview
        const palette = document.getElementById('color-palette');
        if (palette && palette.children[index]) {
            const preview = palette.children[index].querySelector('.color-swatch-preview');
            if (preview) {
                preview.style.backgroundColor = hexColor;
            }
        }
        
        // Send update to backend to persist changes
        const rgb = this.hexToRgb(hexColor);
        try {
            const response = await fetch('/api/parameters', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: this.currentTab,
                    red: rgb.r,
                    green: rgb.g,
                    blue: rgb.b,
                    color_index: index
                })
            });
            
            if (response.ok) {
                // Reload state to ensure persistence
                await this.loadState();
                // Re-render palette to reflect persisted state
                const updatedPatternSettings = this.getPatternSettings(tabName, pattern);
                this.renderColorPalette(tabName, updatedPatternSettings.colors);
            }
        } catch (error) {
            console.error('Failed to update color:', error);
        }
    }


    async updateBrightness() {
        if (!this.currentTab) return;
        
        const brightness = parseInt(document.getElementById('brightness-slider').value) || 0;
        
        try {
            await fetch('/api/parameters', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: this.currentTab,
                    brightness: brightness
                })
            });
        } catch (error) {
            console.error('Failed to update brightness:', error);
        }
    }

    async updateDelay() {
        if (!this.currentTab) return;
        
        const sliderValue = parseInt(document.getElementById('delay-slider').value);
        const pattern = this.state.lights[this.currentTab].settings.pattern;
        const patternConfig = this.state.patterns[pattern] || {};
        const minDelay = patternConfig.min_delay || 10;
        const maxDelay = patternConfig.max_delay || 10000;
        
        try {
            await fetch('/api/parameters', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: this.currentTab,
                    delay_slider: sliderValue
                })
            });
        } catch (error) {
            console.error('Failed to update delay:', error);
        }
    }

    async updateNParams() {
        if (!this.currentTab) return;
        
        const nParams = {};
        for (let i = 1; i <= 8; i++) {
            nParams[`n${i}`] = parseInt(document.getElementById(`n${i}-input`).value) || 0;
        }
        
        try {
            await fetch('/api/parameters', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    tab_name: this.currentTab,
                    ...nParams
                })
            });
        } catch (error) {
            console.error('Failed to update n params:', error);
        }
    }

    debounceUpdate(key, callback) {
        if (this.updateTimeouts[key]) {
            clearTimeout(this.updateTimeouts[key]);
        }
        this.updateTimeouts[key] = setTimeout(callback, 100);
    }

    delayToSlider(delayMs, minDelay = 10, maxDelay = 10000) {
        if (delayMs <= minDelay) return 0;
        if (delayMs >= maxDelay) return 1000;
        if (minDelay === maxDelay) return 0;
        return Math.floor(1000 * Math.log(delayMs / minDelay) / Math.log(maxDelay / minDelay));
    }

    sliderToDelay(sliderValue, minDelay = 10, maxDelay = 10000) {
        if (sliderValue <= 0) return minDelay;
        if (sliderValue >= 1000) return maxDelay;
        if (minDelay === maxDelay) return minDelay;
        return Math.floor(minDelay * Math.pow(maxDelay / minDelay, sliderValue / 1000));
    }

    updateDelayValue(sliderValue, minDelay, maxDelay) {
        if (!minDelay || !maxDelay) {
            const pattern = this.currentTab ? this.state.lights[this.currentTab]?.settings?.pattern : 'on';
            const patternConfig = this.state.patterns[pattern] || {};
            minDelay = patternConfig.min_delay || 10;
            maxDelay = patternConfig.max_delay || 10000;
        }
        const delay = this.sliderToDelay(parseInt(sliderValue), minDelay, maxDelay);
        document.getElementById('delay-value').textContent = `${delay} ms`;
    }

    hexToRgb(hex) {
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
        } : { r: 0, g: 0, b: 0 };
    }

    rgbToHex(r, g, b) {
        return `#${[r, g, b].map(x => {
            const hex = x.toString(16);
            return hex.length === 1 ? '0' + hex : hex;
        }).join('')}`;
    }

    showAddTabModal() {
        document.getElementById('new-zone-name').value = '';
        document.getElementById('new-zone-ids').value = '1';
        document.getElementById('add-zone-modal').classList.add('active');
    }

    async createTab() {
        const name = document.getElementById('new-zone-name').value.trim();
        const idsStr = document.getElementById('new-zone-ids').value.trim();
        const ids = idsStr.split(',').map(id => id.trim()).filter(id => id);
        
        if (!name) {
            alert('Zone name cannot be empty');
            return;
        }
        
        try {
            const response = await fetch('/zones', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ name, ids })
            });
            
            if (response.ok) {
                await this.loadState();
                this.renderTabs();
                this.selectTab(name);
                this.hideModal('add-zone-modal');
            } else {
                const error = await response.json();
                alert(error.error || 'Failed to create zone');
            }
        } catch (error) {
            console.error('Failed to create zone:', error);
            alert('Failed to create zone');
        }
    }

    showEditTabModal() {
        if (!this.currentTab) {
            alert('Please select a zone first');
            return;
        }
        
        const light = this.state.lights[this.currentTab];
        document.getElementById('edit-zone-name').value = this.currentTab;
        document.getElementById('edit-zone-ids').value = light.names.join(', ');
        document.getElementById('edit-zone-modal').classList.add('active');
    }

    async updateTab() {
        const newName = document.getElementById('edit-zone-name').value.trim();
        const idsStr = document.getElementById('edit-zone-ids').value.trim();
        const ids = idsStr.split(',').map(id => id.trim()).filter(id => id);
        
        if (!newName) {
            alert('Zone name cannot be empty');
            return;
        }
        
        try {
            const response = await fetch(`/zones/${this.currentTab}`, {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ name: newName, ids })
            });
            
            if (response.ok) {
                await this.loadState();
                this.renderTabs();
                this.selectTab(newName);
                this.hideModal('edit-zone-modal');
            } else {
                const error = await response.json();
                alert(error.error || 'Failed to update zone');
            }
        } catch (error) {
            console.error('Failed to update zone:', error);
            alert('Failed to update zone');
        }
    }

    async deleteCurrentTab() {
        if (!this.currentTab) {
            alert('Please select a zone first');
            return;
        }
        
        if (!confirm(`Are you sure you want to delete the zone '${this.currentTab}'?`)) {
            return;
        }
        
        try {
            const response = await fetch(`/zones/${this.currentTab}`, {
                method: 'DELETE'
            });
            
            if (response.ok) {
                await this.loadState();
                this.renderTabs();
                if (this.state.zone_order.length > 0) {
                    this.selectTab(this.state.zone_order[0]);
                } else {
                    this.currentTab = null;
                    document.getElementById('zone-content').innerHTML = '<p>No tabs available. Create a new zone to get started.</p>';
                }
            }
        } catch (error) {
            console.error('Failed to delete zone:', error);
            alert('Failed to delete zone');
        }
    }

    async addColorToPalette() {
        if (!this.currentTab) return;
        
        const pattern = this.state.lights[this.currentTab].settings.pattern;
        const patternSettings = this.getPatternSettings(this.currentTab, pattern);
        patternSettings.colors.push('#000000');
        this.selectedColorIndex = patternSettings.colors.length - 1;
        this.renderColorPalette(this.currentTab, patternSettings.colors);
    }

    async removeSelectedColor() {
        if (!this.currentTab) return;
        
        const pattern = this.state.lights[this.currentTab].settings.pattern;
        const patternSettings = this.getPatternSettings(this.currentTab, pattern);
        
        if (patternSettings.colors.length <= 1) {
            alert('There must be at least one color in the palette');
            return;
        }
        
        patternSettings.colors.splice(this.selectedColorIndex, 1);
        if (this.selectedColorIndex >= patternSettings.colors.length) {
            this.selectedColorIndex = patternSettings.colors.length - 1;
        }
        this.renderColorPalette(this.currentTab, patternSettings.colors);
    }

    async showColorPalette() {
        const modal = document.getElementById('color-palette-modal');
        modal.classList.add('active');
        // Update current profile display in palette modal
        const profileNameDisplay = document.getElementById('palette-current-profile-name');
        if (profileNameDisplay) {
            profileNameDisplay.textContent = this.state.current_profile || 'None';
        }
        await this.loadProfilePalette();
    }

    async showProfiles() {
        const modal = document.getElementById('profiles-modal');
        modal.classList.add('active');
        
        await this.loadProfiles();
        await this.loadProfilePalette();
    }

    async loadProfiles() {
        try {
            const response = await fetch('/profiles');
            const profiles = await response.json();
            
            const profilesList = document.getElementById('profiles-list');
            profilesList.innerHTML = '';
            
            // Controllers return dict with IDs as keys, convert to array of names
            const profileNames = Object.keys(profiles || {});
            const profileData = Object.values(profiles || {});
            
            // Find current profile (first one or from settings)
            const currentProfile = profileNames.length > 0 ? profileNames[0] : '';
            this.state.current_profile = currentProfile;
            if (currentProfile && profiles[currentProfile]) {
                this.state.color_palette = profiles[currentProfile].color_palette || [];
            }
            this.updateCurrentProfileDisplay();
            
            if (profileNames.length === 0) {
                profilesList.innerHTML = '<p style="text-align: center; color: #888;">No profiles found</p>';
            } else {
                profileNames.forEach(profileId => {
                    const profile = profiles[profileId];
                    const profileName = profile.name || profileId;
                    const profileItem = document.createElement('div');
                    profileItem.style.cssText = 'display: flex; align-items: center; justify-content: space-between; padding: 0.75rem; background-color: #3a3a3a; border-radius: 4px; margin-bottom: 0.5rem;';
                    
                    const profileLabel = document.createElement('span');
                    profileLabel.textContent = profileName;
                    if (profileId === currentProfile || profileName === currentProfile) {
                        profileLabel.textContent = `✓ ${profileName}`;
                        profileLabel.style.fontWeight = 'bold';
                        profileLabel.style.color = '#FFD700';
                    }

                    const actionsContainer = document.createElement('div');
                    actionsContainer.style.cssText = 'display: flex; gap: 0.5rem;';
                    
                    const loadButton = document.createElement('button');
                    loadButton.className = 'btn btn-small';
                    loadButton.textContent = 'Load';
                    loadButton.addEventListener('click', () => this.loadProfile(profileId));

                    const deleteButton = document.createElement('button');
                    deleteButton.className = 'btn btn-small btn-danger';
                    deleteButton.textContent = 'Delete';
                    deleteButton.addEventListener('click', () => this.deleteProfile(profileId));
                    
                    actionsContainer.appendChild(loadButton);
                    actionsContainer.appendChild(deleteButton);
                    
                    profileItem.appendChild(profileLabel);
                    profileItem.appendChild(actionsContainer);
                    profilesList.appendChild(profileItem);
                });
            }
        } catch (error) {
            console.error('Failed to load profiles:', error);
            alert('Failed to load profiles');
        }
    }

    async deleteProfile(profileName) {
        if (!confirm(`Delete profile '${profileName}'? This cannot be undone.`)) {
            return;
        }
        
        try {
            const response = await fetch(`/profiles/${profileName}`, {
                method: 'DELETE'
            });
            
            if (response.ok) {
                await this.loadProfiles();
                // If the current profile was deleted, clear current state tabs
                if (this.state.current_profile === profileName) {
                    this.state.current_profile = '';
                    this.state.lights = {};
                    this.state.zone_order = [];
                    this.renderTabs();
                    document.getElementById('zone-content').innerHTML = '<p>No tabs available. Create a new zone to get started.</p>';
                    this.updateCurrentProfileDisplay();
                }
            } else {
                const error = await response.json();
                alert(error.error || 'Failed to delete profile');
            }
        } catch (error) {
            console.error('Failed to delete profile:', error);
            alert('Failed to delete profile');
        }
    }

    async loadProfile(profileName) {
        try {
            const response = await fetch(`/profiles/${profileName}`, {
                method: 'POST'
            });
            
            if (response.ok) {
                await this.loadState();
                this.renderTabs();
                if (this.state.zone_order.length > 0) {
                    this.selectTab(this.state.zone_order[0]);
                } else {
                    this.currentTab = null;
                }
                await this.loadProfiles(); // Refresh the profiles list
            } else {
                const error = await response.json();
                alert(error.error || 'Failed to load profile');
            }
        } catch (error) {
            console.error('Failed to load profile:', error);
            alert('Failed to load profile');
        }
    }

    async createProfile() {
        const nameInput = document.getElementById('new-profile-name');
        const profileName = nameInput.value.trim();
        
        if (!profileName) {
            alert('Profile name cannot be empty');
            return;
        }
        
        try {
            const response = await fetch('/profiles', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ name: profileName })
            });
            
            if (response.ok) {
                nameInput.value = '';
                await this.loadProfiles();
                alert(`Profile '${profileName}' created successfully`);
            } else {
                const error = await response.json();
                alert(error.error || 'Failed to create profile');
            }
        } catch (error) {
            console.error('Failed to create profile:', error);
            alert('Failed to create profile');
        }
    }

    async loadProfilePalette() {
        const currentProfile = this.state.current_profile;
        if (!currentProfile) {
            this.renderProfilePalette([]);
            return;
        }
        
        try {
            // TODO: /profiles/<id>/palette endpoint doesn't exist, load profile and extract palette
            const profileResponse = await fetch(`/profiles/${currentProfile}`);
            const profile = await profileResponse.json();
            const response = { json: async () => ({ color_palette: profile.color_palette || [] }) };
            if (response.ok) {
                const data = await response.json();
                this.renderProfilePalette(data.color_palette || []);
            } else {
                this.renderProfilePalette([]);
            }
        } catch (error) {
            console.error('Failed to load profile palette:', error);
            this.renderProfilePalette([]);
        }
    }

    renderProfilePalette(colors) {
        // Render in profiles modal
        const container = document.getElementById('profile-palette-container');
        if (container) {
            container.innerHTML = '';
            colors.forEach((color, index) => {
                const swatch = this.createPaletteSwatch(color, index);
                container.appendChild(swatch);
            });
        }
        
        // Render in color palette modal
        const paletteContainer = document.getElementById('palette-container');
        if (paletteContainer) {
            paletteContainer.innerHTML = '';
            colors.forEach((color, index) => {
                const swatch = this.createPaletteSwatch(color, index);
                paletteContainer.appendChild(swatch);
            });
        }
    }

    createPaletteSwatch(color, index) {
        const swatch = document.createElement('div');
        swatch.style.cssText = 'width: 40px; height: 40px; background-color: ' + color + '; border: 2px solid #4a4a4a; border-radius: 4px; cursor: pointer; position: relative;';
        swatch.title = `Click to apply ${color} to selected color`;
        
        // Click to apply color to currently selected color in active zone
        swatch.addEventListener('click', (e) => {
            // Only apply if not clicking the remove button
            if (e.target === swatch || !e.target.closest('button')) {
                this.applyPaletteColorToSelected(color);
            }
        });
        
        const removeBtn = document.createElement('button');
        removeBtn.textContent = '×';
        removeBtn.style.cssText = 'position: absolute; top: -8px; right: -8px; width: 20px; height: 20px; border-radius: 50%; background-color: #ff4444; color: white; border: none; cursor: pointer; font-size: 14px; line-height: 1; display: flex; align-items: center; justify-content: center; z-index: 10;';
        removeBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            this.removePaletteColor(index);
        });
        
        swatch.appendChild(removeBtn);
        return swatch;
    }

    applyPaletteColorToSelected(paletteColor) {
        if (!this.currentTab) {
            alert('No zone selected. Please select a zone first.');
            return;
        }
        
        const pattern = this.state.lights[this.currentTab].settings.pattern;
        const patternSettings = this.getPatternSettings(this.currentTab, pattern);
        
        if (patternSettings.colors.length === 0) {
            alert('No colors in the current pattern. Add a color first.');
            return;
        }
        
        // Apply the palette color to the currently selected color index
        const selectedIndex = this.selectedColorIndex;
        if (selectedIndex >= 0 && selectedIndex < patternSettings.colors.length) {
            this.updateColorInPalette(this.currentTab, selectedIndex, paletteColor);
        } else {
            // If no color is selected, apply to the first color
            this.updateColorInPalette(this.currentTab, 0, paletteColor);
        }
    }

    async addPaletteColor() {
        const colorInput = document.getElementById('new-palette-color');
        if (!colorInput) return;
        await this.addPaletteColorFromInput(colorInput);
    }

    async addPaletteColorFromModal() {
        const colorInput = document.getElementById('palette-new-color');
        if (!colorInput) return;
        await this.addPaletteColorFromInput(colorInput);
    }

    async addPaletteColorFromInput(colorInput) {
        const color = colorInput.value;
        const currentProfile = this.state.current_profile;
        
        if (!currentProfile) {
            alert('No profile selected');
            return;
        }
        
        try {
            const currentPalette = this.state.color_palette || [];
            if (currentPalette.includes(color)) {
                alert('Color already in palette');
                return;
            }
            
            const newPalette = [...currentPalette, color];
            // TODO: /profiles/<id>/palette endpoint doesn't exist, update profile directly
            const profileResponse = await fetch(`/profiles/${currentProfile}`);
            const profile = await profileResponse.json();
            profile.color_palette = colorPalette;
            const response = await fetch(`/profiles/${currentProfile}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ color_palette: newPalette })
            });
            
            if (response.ok) {
                this.state.color_palette = newPalette;
                await this.loadProfilePalette();
            } else {
                alert('Failed to add color to palette');
            }
        } catch (error) {
            console.error('Failed to add palette color:', error);
            alert('Failed to add color to palette');
        }
    }

    async removePaletteColor(index) {
        const currentProfile = this.state.current_profile;
        
        if (!currentProfile) {
            alert('No profile selected');
            return;
        }
        
        try {
            const currentPalette = this.state.color_palette || [];
            const newPalette = currentPalette.filter((_, i) => i !== index);
            
            // TODO: /profiles/<id>/palette endpoint doesn't exist, update profile directly
            const profileResponse = await fetch(`/profiles/${currentProfile}`);
            const profile = await profileResponse.json();
            profile.color_palette = colorPalette;
            const response = await fetch(`/profiles/${currentProfile}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ color_palette: newPalette })
            });
            
            if (response.ok) {
                this.state.color_palette = newPalette;
                await this.loadProfilePalette();
            } else {
                alert('Failed to remove color from palette');
            }
        } catch (error) {
            console.error('Failed to remove palette color:', error);
            alert('Failed to remove color from palette');
        }
    }

    showPaletteQuickSelect(wrapper, tabName, colorIndex, colorPickerInput) {
        const palette = this.state.color_palette || [];
        if (palette.length === 0) {
            // No palette colors, allow native picker to open
            return;
        }
        
        // Store context for the modal
        this.quickPaletteContext = {
            tabName: tabName,
            colorIndex: colorIndex,
            colorPickerInput: colorPickerInput
        };
        
        // Show the modal
        const modal = document.getElementById('quick-palette-modal');
        modal.classList.add('active');
        
        // Render palette colors in the modal
        this.renderQuickPalette(palette);
    }

    renderQuickPalette(palette) {
        const container = document.getElementById('quick-palette-container');
        if (!container) return;
        
        container.innerHTML = '';
        
        if (palette.length === 0) {
            container.innerHTML = '<p style="text-align: center; color: #888; width: 100%;">No colors in palette</p>';
            return;
        }
        
        palette.forEach((color) => {
            const colorBtn = document.createElement('div');
            colorBtn.style.cssText = `width: 80px; height: 80px; background-color: ${color}; border: 3px solid #4a4a4a; border-radius: 8px; cursor: pointer; flex-shrink: 0; position: relative; transition: transform 0.2s, border-color 0.2s;`;
            colorBtn.title = color;
            
            // Add color hex label
            const label = document.createElement('div');
            label.style.cssText = 'position: absolute; bottom: -20px; left: 0; right: 0; text-align: center; font-size: 0.7rem; color: #aaa;';
            label.textContent = color;
            colorBtn.appendChild(label);
            
            colorBtn.addEventListener('mouseenter', () => {
                colorBtn.style.transform = 'scale(1.1)';
                colorBtn.style.borderColor = '#6a5acd';
            });
            colorBtn.addEventListener('mouseleave', () => {
                colorBtn.style.transform = 'scale(1)';
                colorBtn.style.borderColor = '#4a4a4a';
            });
            
            colorBtn.addEventListener('click', () => {
                if (this.quickPaletteContext) {
                    const { tabName, colorIndex, colorPickerInput } = this.quickPaletteContext;
                    this.updateColorInPalette(tabName, colorIndex, color);
                    colorPickerInput.value = color;
                }
                this.hideQuickPaletteModal();
            });
            
            container.appendChild(colorBtn);
        });
    }

    hideQuickPaletteModal() {
        const modal = document.getElementById('quick-palette-modal');
        modal.classList.remove('active');
        this.quickPaletteContext = null;
    }

    useColorPickerFromQuickPalette() {
        if (this.quickPaletteContext && this.quickPaletteContext.colorPickerInput) {
            const colorPickerInput = this.quickPaletteContext.colorPickerInput;
            // Mark that we want to allow native picker
            colorPickerInput.dataset.allowNative = 'true';
            // Temporarily remove the click handler
            if (colorPickerInput._clickHandler) {
                colorPickerInput.removeEventListener('click', colorPickerInput._clickHandler);
            }
            this.hideQuickPaletteModal();
            // Trigger native color picker after closing modal
            setTimeout(() => {
                // Try using showPicker() if available (modern browsers)
                if (colorPickerInput.showPicker) {
                    colorPickerInput.showPicker().catch(() => {
                        // Fallback to click if showPicker fails
                        colorPickerInput.click();
                    });
                } else {
                    // Fallback to click for older browsers
                    colorPickerInput.click();
                }
                // Restore the click handler after a moment
                setTimeout(() => {
                    if (colorPickerInput._clickHandler) {
                        colorPickerInput.addEventListener('click', colorPickerInput._clickHandler);
                    }
                    delete colorPickerInput.dataset.allowNative;
                }, 500);
            }, 200);
        }
    }

    async showPresets() {
        const modal = document.getElementById('presets-modal');
        modal.classList.add('active');
        await this.loadPresets();
    }

    async loadPresets() {
        try {
            const response = await fetch('/presets');
            const data = await response.json();
            
            // Controllers return the full dict, so use it directly
            this.state.presets = data || {};
            
            const presetsList = document.getElementById('presets-list');
            presetsList.innerHTML = '';
            
            const presetNames = Object.keys(this.state.presets);
            if (presetNames.length === 0) {
                presetsList.innerHTML = '<p style="text-align: center; color: #888;">No presets found. Create one to get started.</p>';
            } else {
                presetNames.forEach(presetName => {
                    const preset = this.state.presets[presetName];
                    const presetItem = document.createElement('div');
                    presetItem.style.cssText = 'display: flex; align-items: center; justify-content: space-between; padding: 0.75rem; background-color: #3a3a3a; border-radius: 4px; margin-bottom: 0.5rem;';
                    
                    const presetInfo = document.createElement('div');
                    presetInfo.style.cssText = 'display: flex; flex-direction: column; gap: 0.25rem; flex: 1;';
                    
                    const presetNameLabel = document.createElement('span');
                    presetNameLabel.textContent = presetName;
                    presetNameLabel.style.fontWeight = 'bold';
                    
                    const presetDetails = document.createElement('span');
                    presetDetails.style.fontSize = '0.9em';
                    presetDetails.style.color = '#aaa';
                    presetDetails.textContent = `Pattern: ${preset.pattern} | Brightness: ${preset.brightness} | Delay: ${preset.delay}ms | Colors: ${preset.colors.length}`;
                    
                    presetInfo.appendChild(presetNameLabel);
                    presetInfo.appendChild(presetDetails);
                    
                    const actionsContainer = document.createElement('div');
                    actionsContainer.style.cssText = 'display: flex; gap: 0.5rem;';
                    
                    const applyButton = document.createElement('button');
                    applyButton.className = 'btn btn-small btn-primary';
                    applyButton.textContent = 'Apply';
                    applyButton.addEventListener('click', () => this.applyPreset(presetName));
                    
                    const editButton = document.createElement('button');
                    editButton.className = 'btn btn-small';
                    editButton.textContent = 'Edit';
                    editButton.addEventListener('click', () => this.showPresetEditor(presetName));
                    
                    const deleteButton = document.createElement('button');
                    deleteButton.className = 'btn btn-small btn-danger';
                    deleteButton.textContent = 'Delete';
                    deleteButton.addEventListener('click', () => this.deletePreset(presetName));
                    
                    actionsContainer.appendChild(applyButton);
                    actionsContainer.appendChild(editButton);
                    actionsContainer.appendChild(deleteButton);
                    
                    presetItem.appendChild(presetInfo);
                    presetItem.appendChild(actionsContainer);
                    presetsList.appendChild(presetItem);
                });
            }
        } catch (error) {
            console.error('Failed to load presets:', error);
            alert('Failed to load presets');
        }
    }

    async applyPreset(presetName) {
        if (!this.currentTab) {
            alert('Please select a zone first');
            return;
        }
        
        try {
            // TODO: /presets/<id>/apply endpoint doesn't exist, using pattern/parameters directly
            const preset = this.state.presets[presetName];
            if (!preset) {
                alert('Preset not found');
                return;
            }
            
            // Apply preset using the apply endpoint
            const response = await fetch(`/api/presets/${presetName}/apply`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    tab_name: this.currentTab
                })
            });
            
            if (response.ok) {
                await this.loadState();
                await this.loadTabContent(this.currentTab);
                this.hideModal('presets-modal');
            } else {
                const error = await response.json();
                alert(`Failed to apply preset: ${error.error || 'Unknown error'}`);
            }
        } catch (error) {
            console.error('Failed to apply preset:', error);
            alert('Failed to apply preset');
        }
    }

    async deletePreset(presetName) {
        if (!confirm(`Delete preset '${presetName}'? This cannot be undone.`)) {
            return;
        }
        
        try {
            const response = await fetch(`/presets/${presetName}`, {
                method: 'DELETE'
            });
            
            if (response.ok) {
                await this.loadPresets();
            } else {
                const error = await response.json();
                alert(`Failed to delete preset: ${error.error || 'Unknown error'}`);
            }
        } catch (error) {
            console.error('Failed to delete preset:', error);
            alert('Failed to delete preset');
        }
    }

    showPresetEditor(presetName = null) {
        const modal = document.getElementById('preset-editor-modal');
        const title = document.getElementById('preset-editor-title');
        const nameInput = document.getElementById('preset-name-input');
        const patternSelect = document.getElementById('preset-pattern-select');
        const brightnessSlider = document.getElementById('preset-brightness-slider');
        const brightnessValue = document.getElementById('preset-brightness-value');
        const delayInput = document.getElementById('preset-delay-input');
        const n1Input = document.getElementById('preset-n1-input');
        const n2Input = document.getElementById('preset-n2-input');
        const n3Input = document.getElementById('preset-n3-input');
        const n4Input = document.getElementById('preset-n4-input');
        
        // Store editing preset name
        this.editingPresetName = presetName;
        
        // Populate pattern select
        patternSelect.innerHTML = '';
        const patterns = Object.keys(this.state.patterns || {});
        patterns.forEach(pattern => {
            const option = document.createElement('option');
            option.value = pattern;
            option.textContent = pattern;
            patternSelect.appendChild(option);
        });
        
        if (presetName && this.state.presets[presetName]) {
            // Editing existing preset
            title.textContent = 'Edit Preset';
            const preset = this.state.presets[presetName];
            nameInput.value = presetName;
            nameInput.disabled = false;
            patternSelect.value = preset.pattern;
            brightnessSlider.value = preset.brightness;
            brightnessValue.textContent = preset.brightness;
            delayInput.value = preset.delay;
            n1Input.value = preset.n1;
            n2Input.value = preset.n2;
            n3Input.value = preset.n3;
            n4Input.value = preset.n4;
            this.renderPresetColors(preset.colors);
        } else {
            // Creating new preset
            title.textContent = 'Create Preset';
            nameInput.value = '';
            nameInput.disabled = false;
            patternSelect.value = patterns[0] || 'on';
            brightnessSlider.value = 127;
            brightnessValue.textContent = 127;
            delayInput.value = 100;
            n1Input.value = 10;
            n2Input.value = 10;
            n3Input.value = 10;
            n4Input.value = 10;
            this.renderPresetColors(['#000000']);
        }
        
        this.selectedPresetColorIndex = 0;
        modal.classList.add('active');
    }

    renderPresetColors(colors) {
        const container = document.getElementById('preset-colors-container');
        container.innerHTML = '';
        
        colors.forEach((color, index) => {
            const colorWrapper = document.createElement('div');
            colorWrapper.style.cssText = 'position: relative;';
            
            const colorSwatch = document.createElement('div');
            colorSwatch.style.cssText = `width: 50px; height: 50px; background-color: ${color}; border: 2px solid ${index === this.selectedPresetColorIndex ? '#FFD700' : '#4a4a4a'}; border-radius: 4px; cursor: pointer; position: relative;`;
            colorSwatch.dataset.index = index;
            colorSwatch.addEventListener('click', () => {
                this.selectedPresetColorIndex = index;
                this.renderPresetColors(colors);
            });
            
            const colorPicker = document.createElement('input');
            colorPicker.type = 'color';
            colorPicker.value = color;
            colorPicker.style.cssText = 'position: absolute; top: 0; left: 0; width: 50px; height: 50px; opacity: 0; cursor: pointer;';
            colorPicker.addEventListener('change', (e) => {
                colors[index] = e.target.value;
                this.renderPresetColors(colors);
            });
            
            colorWrapper.appendChild(colorSwatch);
            colorWrapper.appendChild(colorPicker);
            container.appendChild(colorWrapper);
        });
        
        this.presetColors = colors;
    }

    addPresetColor() {
        const colorInput = document.getElementById('preset-new-color');
        const color = colorInput.value;
        
        if (!this.presetColors) {
            this.presetColors = [];
        }
        
        this.presetColors.push(color);
        this.selectedPresetColorIndex = this.presetColors.length - 1;
        this.renderPresetColors(this.presetColors);
    }

    removePresetColor() {
        if (!this.presetColors || this.presetColors.length === 0) {
            return;
        }
        
        if (this.selectedPresetColorIndex >= 0 && this.selectedPresetColorIndex < this.presetColors.length) {
            this.presetColors.splice(this.selectedPresetColorIndex, 1);
            if (this.selectedPresetColorIndex >= this.presetColors.length) {
                this.selectedPresetColorIndex = Math.max(0, this.presetColors.length - 1);
            }
            this.renderPresetColors(this.presetColors);
        }
    }

    loadCurrentTabToPresetEditor() {
        if (!this.currentTab || !this.state.lights[this.currentTab]) {
            alert('Please select a zone first');
            return;
        }
        
        const light = this.state.lights[this.currentTab];
        const settings = light.settings;
        const pattern = settings.pattern || 'on';
        
        // Get pattern-specific settings
        const patternSettings = this.getPatternSettings(this.currentTab, pattern);
        
        const patternSelect = document.getElementById('preset-pattern-select');
        const brightnessSlider = document.getElementById('preset-brightness-slider');
        const brightnessValue = document.getElementById('preset-brightness-value');
        const delayInput = document.getElementById('preset-delay-input');
        const n1Input = document.getElementById('preset-n1-input');
        const n2Input = document.getElementById('preset-n2-input');
        const n3Input = document.getElementById('preset-n3-input');
        const n4Input = document.getElementById('preset-n4-input');
        
        patternSelect.value = pattern;
        brightnessSlider.value = settings.brightness || 127;
        brightnessValue.textContent = settings.brightness || 127;
        delayInput.value = patternSettings.delay || 100;
        n1Input.value = patternSettings.n1 || 10;
        n2Input.value = patternSettings.n2 || 10;
        n3Input.value = patternSettings.n3 || 10;
        n4Input.value = patternSettings.n4 || 10;
        
        this.renderPresetColors(patternSettings.colors || ['#000000']);
    }

    async savePreset() {
        const nameInput = document.getElementById('preset-name-input');
        const patternSelect = document.getElementById('preset-pattern-select');
        const brightnessSlider = document.getElementById('preset-brightness-slider');
        const delayInput = document.getElementById('preset-delay-input');
        const n1Input = document.getElementById('preset-n1-input');
        const n2Input = document.getElementById('preset-n2-input');
        const n3Input = document.getElementById('preset-n3-input');
        const n4Input = document.getElementById('preset-n4-input');
        
        const presetName = nameInput.value.trim();
        if (!presetName) {
            alert('Please enter a preset name');
            return;
        }
        
        if (!this.presetColors || this.presetColors.length === 0) {
            alert('Please add at least one color');
            return;
        }
        
        const presetData = {
            name: presetName,
            pattern: patternSelect.value,
            brightness: parseInt(brightnessSlider.value),
            delay: parseInt(delayInput.value),
            n1: parseInt(n1Input.value),
            n2: parseInt(n2Input.value),
            n3: parseInt(n3Input.value),
            n4: parseInt(n4Input.value),
            colors: this.presetColors
        };
        
        try {
            let response;
            if (this.editingPresetName) {
                // Update existing preset
                response = await fetch(`/presets/${this.editingPresetName}`, {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(presetData)
                });
            } else {
                // Create new preset
                response = await fetch('/presets', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(presetData)
                });
            }
            
            if (response.ok) {
                await this.loadPresets();
                this.hideModal('preset-editor-modal');
                this.editingPresetName = null;
            } else {
                const error = await response.json();
                alert(`Failed to save preset: ${error.error || 'Unknown error'}`);
            }
        } catch (error) {
            console.error('Failed to save preset:', error);
            alert('Failed to save preset');
        }
    }

    hideModal(modalId) {
        document.getElementById(modalId).classList.remove('active');
    }
}

// Initialize app when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
    new LightingController();
});

