// Node Details Component
class NodeDetailsComponent extends Component {
    constructor(container, viewModel, eventBus) {
        super(container, viewModel, eventBus);
        this.suppressLoadingUI = false;
    }

    // Helper functions for color conversion
    rgbIntToHex(rgbInt) {
        if (!rgbInt && rgbInt !== 0) return '#000000';
        const num = parseInt(rgbInt);
        if (isNaN(num)) return '#000000';
        const r = (num >> 16) & 255;
        const g = (num >> 8) & 255;
        const b = num & 255;
        return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
    }

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

    // Format flash size in human readable format
    formatFlashSize(bytes) {
        if (!bytes || bytes === 0) return 'Unknown';
        
        const units = ['B', 'KB', 'MB', 'GB'];
        let size = bytes;
        let unitIndex = 0;
        
        while (size >= 1024 && unitIndex < units.length - 1) {
            size /= 1024;
            unitIndex++;
        }
        
        return `${size.toFixed(1)} ${units[unitIndex]}`;
    }

    // Parameter component renderers
    renderSelectComponent(p, formId, pidx) {
        return `<select id="${formId}-field-${pidx}" data-param-name="${p.name}" data-param-location="${p.location || 'body'}" data-param-type="${p.type || 'string'}" data-param-required="${p.required ? '1' : '0'}" class="param-input">${p.values.map(v => `<option value="${v}">${v}</option>`).join('')}</select>`;
    }

    renderColorComponent(p, formId, pidx) {
        const defaultValue = p.default !== undefined ? p.default : (Array.isArray(p.values) && p.values.length === 1) ? p.values[0] : 0;
        return `<div class="color-input-container">
            <input id="${formId}-field-${pidx}" 
                   data-param-name="${p.name}" 
                   data-param-location="${p.location || 'body'}" 
                   data-param-type="${p.type || 'string'}" 
                   data-param-required="${p.required ? '1' : '0'}" 
                   class="param-input color-picker" 
                   type="color" 
                   value="${this.rgbIntToHex(defaultValue)}">
            <input type="text" 
                   class="color-rgb-display" 
                   readonly 
                   value="${defaultValue}" 
                   style="margin-left: 5px; width: 80px; font-size: 0.8em;">
           </div>`;
    }

    renderNumberRangeComponent(p, formId, pidx) {
        const defaultValue = p.default !== undefined ? p.default : 0;
        const maxValue = p.value || 100;
        return `<div class="number-range-container">
            <input id="${formId}-field-${pidx}" 
                   data-param-name="${p.name}" 
                   data-param-location="${p.location || 'body'}" 
                   data-param-type="${p.type || 'string'}" 
                   data-param-required="${p.required ? '1' : '0'}" 
                   class="param-input range-slider" 
                   type="range" 
                   min="0" 
                   max="${maxValue}" 
                   value="${defaultValue}">
            <div class="range-display">
                <span class="range-value">${defaultValue}</span>
                <span class="range-max">/ ${maxValue}</span>
            </div>
           </div>`;
    }

    renderTextComponent(p, formId, pidx) {
        const defaultValue = p.default !== undefined ? p.default : (Array.isArray(p.values) && p.values.length === 1) ? p.values[0] : '';
        return `<input id="${formId}-field-${pidx}" 
                      data-param-name="${p.name}" 
                      data-param-location="${p.location || 'body'}" 
                      data-param-type="${p.type || 'string'}" 
                      data-param-required="${p.required ? '1' : '0'}" 
                      class="param-input" 
                      type="text" 
                      placeholder="${p.location || 'body'} • ${p.type || 'string'}" 
                      value="${defaultValue}">`;
    }

    renderBooleanComponent(p, formId, pidx) {
        const defaultValue = p.default !== undefined ? p.default : false;
        const checked = defaultValue ? 'checked' : '';
        return `<div class="boolean-input-container">
            <input id="${formId}-field-${pidx}" 
                   data-param-name="${p.name}" 
                   data-param-location="${p.location || 'body'}" 
                   data-param-type="${p.type || 'boolean'}" 
                   data-param-required="${p.required ? '1' : '0'}" 
                   class="param-input boolean-checkbox" 
                   type="checkbox" 
                   ${checked}>
            <label for="${formId}-field-${pidx}" class="boolean-label">${p.name}</label>
        </div>`;
    }

    // Component map for parameter types
    getParameterComponentMap() {
        const components = {
            select: this.renderSelectComponent,
            color: this.renderColorComponent,
            numberRange: this.renderNumberRangeComponent,
            boolean: this.renderBooleanComponent,
            text: this.renderTextComponent
        };
        
        // Bind all methods to this context
        return Object.fromEntries(
            Object.entries(components).map(([key, method]) => [key, method.bind(this)])
        );
    }

    // Component type determination rules
    getComponentType(p) {
        const typeRules = [
            { condition: () => Array.isArray(p.values) && p.values.length > 1, type: 'select' },
            { condition: () => p.type === 'color', type: 'color' },
            { condition: () => p.type === 'numberRange', type: 'numberRange' },
            { condition: () => p.type === 'boolean', type: 'boolean' }
        ];
        
        const matchedRule = typeRules.find(rule => rule.condition());
        return matchedRule ? matchedRule.type : 'text';
    }

    // Main parameter renderer that uses the component map
    renderParameterComponent(p, formId, pidx) {
        const componentMap = this.getParameterComponentMap();
        const componentType = this.getComponentType(p);
        const renderer = componentMap[componentType];
        
        return renderer(p, formId, pidx);
    }



    setupViewModelListeners() {
        this.subscribeToProperty('nodeStatus', this.handleNodeStatusUpdate.bind(this));
        this.subscribeToProperty('tasks', this.handleTasksUpdate.bind(this));
        this.subscribeToProperty('isLoading', this.handleLoadingUpdate.bind(this));
        this.subscribeToProperty('error', this.handleErrorUpdate.bind(this));
        this.subscribeToProperty('activeTab', this.handleActiveTabUpdate.bind(this));
        this.subscribeToProperty('endpoints', this.handleEndpointsUpdate.bind(this));
        this.subscribeToProperty('monitoringResources', this.handleMonitoringResourcesUpdate.bind(this));
    }

    // Handle node status update
    handleNodeStatusUpdate(newStatus, previousStatus) {
        if (newStatus && !this.viewModel.get('isLoading')) {
            this.renderNodeDetails(newStatus, this.viewModel.get('tasks'), this.viewModel.get('endpoints'), this.viewModel.get('monitoringResources'));
        }
    }

    // Handle tasks update
    handleTasksUpdate(newTasks, previousTasks) {
        const nodeStatus = this.viewModel.get('nodeStatus');
        if (nodeStatus && !this.viewModel.get('isLoading')) {
            this.renderNodeDetails(nodeStatus, newTasks, this.viewModel.get('endpoints'), this.viewModel.get('monitoringResources'));
        }
    }

    // Handle loading state update
    handleLoadingUpdate(isLoading) {
        if (isLoading) {
            if (this.suppressLoadingUI) return;
            this.renderLoading('<div class="loading-details">Loading detailed information...</div>');
        }
    }

    // Handle error state update
    handleErrorUpdate(error) {
        if (error) {
            this.renderError(`Error loading node details: ${error}`);
        }
    }

    // Handle active tab update
    handleActiveTabUpdate(newTab, previousTab) {
        // Update tab UI without full re-render
        this.updateActiveTab(newTab, previousTab);
    }

    // Handle endpoints update
    handleEndpointsUpdate(newEndpoints, previousEndpoints) {
        const nodeStatus = this.viewModel.get('nodeStatus');
        const tasks = this.viewModel.get('tasks');
        if (nodeStatus && !this.viewModel.get('isLoading')) {
            this.renderNodeDetails(nodeStatus, tasks, newEndpoints, this.viewModel.get('monitoringResources'));
        }
    }

    // Handle monitoring resources update
    handleMonitoringResourcesUpdate(newResources, previousResources) {
        const nodeStatus = this.viewModel.get('nodeStatus');
        const tasks = this.viewModel.get('tasks');
        const endpoints = this.viewModel.get('endpoints');
        if (nodeStatus && !this.viewModel.get('isLoading')) {
            this.renderNodeDetails(nodeStatus, tasks, endpoints, newResources);
        }
    }

    // Labels editor handlers
    handleAddLabel() {
        const keyInput = this.findElement('#label-key');
        const valueInput = this.findElement('#label-value');
        
        if (!keyInput || !valueInput) return;
        
        const key = keyInput.value.trim();
        const value = valueInput.value.trim();
        
        if (!key || !value) return;
        
        // Check if key already exists
        const existingLabel = this.findElement(`.label-item[data-key="${this.escapeHtml(key)}"]`);
        if (existingLabel) {
            this.showMessage(`Label '${key}' already exists`, 'warning');
            return;
        }
        
        // Add the label to the UI
        this.addLabelToUI(key, value);
        
        // Clear inputs
        keyInput.value = '';
        valueInput.value = '';
        
        // Enable save button
        const saveBtn = this.findElement('.save-labels-btn');
        if (saveBtn) {
            saveBtn.disabled = false;
        }
        
        this.showMessage(`Label '${key}' added`, 'success');
    }

    handleRemoveLabel(key) {
        const labelItem = this.findElement(`.label-item[data-key="${this.escapeHtml(key)}"]`);
        if (labelItem) {
            labelItem.remove();
            
            // Enable save button
            const saveBtn = this.findElement('.save-labels-btn');
            if (saveBtn) {
                saveBtn.disabled = false;
            }
            
            this.showMessage(`Label '${key}' removed`, 'success');
        }
    }

    async handleSaveLabels() {
        const saveBtn = this.findElement('.save-labels-btn');
        if (!saveBtn) return;
        
        // Get current labels from UI
        const labels = this.getCurrentLabelsFromUI();
        
        // Show loading state
        const originalText = saveBtn.innerHTML;
        saveBtn.disabled = true;
        saveBtn.innerHTML = `
            <svg class="spinning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                <path d="M1 4v6h6" />
                <path d="M23 20v-6h-6" />
                <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
            </svg>
            Saving...
        `;
        
        try {
            const nodeIp = this.viewModel.get('nodeIp');
            if (!nodeIp) {
                throw new Error('No node IP available');
            }
            
            await window.apiClient.setNodeLabels(nodeIp, labels);
            
            // Disable save button
            saveBtn.disabled = true;
            saveBtn.innerHTML = originalText;
            
            this.showMessage('Labels saved successfully', 'success');
            
            // Trigger a cluster update to refresh member cards with new labels
            // Add a small delay to allow the node to update its member list
            setTimeout(() => {
                this.triggerClusterUpdate();
            }, 1000);
            
            // Don't refresh the entire node details - just update the labels in the current view
            // The labels are already updated in the UI, no need to reload everything
            
        } catch (error) {
            logger.error('Failed to save labels:', error);
            saveBtn.disabled = false;
            saveBtn.innerHTML = originalText;
            this.showMessage(`Failed to save labels: ${error.message}`, 'error');
        }
    }

    addLabelToUI(key, value) {
        const labelsList = this.findElement('.labels-list');
        if (!labelsList) return;
        
        // Remove no-labels message if it exists
        const noLabels = labelsList.querySelector('.no-labels');
        if (noLabels) {
            noLabels.remove();
        }
        
        const labelHtml = `
            <div class="label-item" data-key="${this.escapeHtml(key)}">
                <div class="label-content">
                    <span class="label-key">${this.escapeHtml(key)}</span>
                    <span class="label-separator">=</span>
                    <span class="label-value">${this.escapeHtml(value)}</span>
                </div>
                <button class="label-remove-btn" data-key="${this.escapeHtml(key)}" title="Remove label">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                        <path d="M18 6L6 18M6 6l12 12"/>
                    </svg>
                </button>
            </div>
        `;
        
        labelsList.insertAdjacentHTML('beforeend', labelHtml);
        
        // Re-setup event listeners for the new remove button
        const newRemoveBtn = labelsList.querySelector(`.label-remove-btn[data-key="${this.escapeHtml(key)}"]`);
        if (newRemoveBtn) {
            this.addEventListener(newRemoveBtn, 'click', (e) => {
                const key = e.target.closest('.label-remove-btn').dataset.key;
                this.handleRemoveLabel(key);
            });
        }
    }

    getCurrentLabelsFromUI() {
        const labels = {};
        const labelItems = this.findAllElements('.label-item');
        
        labelItems.forEach(item => {
            const key = item.dataset.key;
            const valueElement = item.querySelector('.label-value');
            if (key && valueElement) {
                labels[key] = valueElement.textContent;
            }
        });
        
        return labels;
    }

    showMessage(message, type = 'info') {
        // Create a temporary message element
        const messageEl = document.createElement('div');
        messageEl.className = `labels-message labels-message-${type}`;
        messageEl.textContent = message;
        
        // Add to the labels section
        const labelsSection = this.findElement('.labels-section');
        if (labelsSection) {
            labelsSection.appendChild(messageEl);
            
            // Remove after 3 seconds
            setTimeout(() => {
                if (messageEl.parentNode) {
                    messageEl.remove();
                }
            }, 3000);
        }
    }

    async triggerClusterUpdate() {
        try {
            // Trigger a server-side cluster refresh to update the UI
            await window.apiClient.request('/api/cluster/refresh', {
                method: 'POST',
                body: { reason: 'labels_updated' }
            });
        } catch (error) {
            logger.error('Failed to trigger cluster refresh:', error);
        }
    }

    render() {
        const nodeStatus = this.viewModel.get('nodeStatus');
        const tasks = this.viewModel.get('tasks');
        const isLoading = this.viewModel.get('isLoading');
        const error = this.viewModel.get('error');
        const endpoints = this.viewModel.get('endpoints');
        const monitoringResources = this.viewModel.get('monitoringResources');

        if (isLoading) {
            this.renderLoading('<div class="loading-details">Loading detailed information...</div>');
            return;
        }

        if (error) {
            this.renderError(`Error loading node details: ${error}`);
            return;
        }

        if (!nodeStatus) {
            this.renderEmpty('<div class="loading-details">No node status available</div>');
            return;
        }

        this.renderNodeDetails(nodeStatus, tasks, endpoints, monitoringResources);
    }

    renderNodeDetails(nodeStatus, tasks, endpoints, monitoringResources) {
        // Use persisted active tab from the view model, default to 'status'
        const activeTab = (this.viewModel && typeof this.viewModel.get === 'function' && this.viewModel.get('activeTab')) || 'status';
        logger.debug('NodeDetailsComponent: Rendering with activeTab:', activeTab);

        // Labels are already shown in the member card header, so we don't need to show them again here
        const labelsBar = '';

        const html = `
            ${labelsBar}
            <div class="tabs-container">
                <div class="tabs-header">
                    <button class="tab-button ${activeTab === 'status' ? 'active' : ''}" data-tab="status">Status</button>
                    <button class="tab-button ${activeTab === 'labels' ? 'active' : ''}" data-tab="labels">Labels</button>
                    <button class="tab-button ${activeTab === 'endpoints' ? 'active' : ''}" data-tab="endpoints">Endpoints</button>
                    <button class="tab-button ${activeTab === 'tasks' ? 'active' : ''}" data-tab="tasks">Tasks</button>
                    <button class="tab-button ${activeTab === 'firmware' ? 'active' : ''}" data-tab="firmware">Firmware</button>
                    <button class="tab-refresh-btn" title="Refresh current tab" aria-label="Refresh">
                        <svg class="refresh-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                            <path d="M1 4v6h6" />
                            <path d="M23 20v-6h-6" />
                            <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
                        </svg>
                    </button>
                </div>
                
                <div class="tab-content ${activeTab === 'status' ? 'active' : ''}" id="status-tab">
                    ${this.renderStatusTab(nodeStatus, monitoringResources)}
                </div>
                
                <div class="tab-content ${activeTab === 'labels' ? 'active' : ''}" id="labels-tab">
                    ${this.renderLabelsTab(nodeStatus)}
                </div>
                
                <div class="tab-content ${activeTab === 'endpoints' ? 'active' : ''}" id="endpoints-tab">
                    ${this.renderEndpointsTab(endpoints)}
                </div>
                
                
                <div class="tab-content ${activeTab === 'tasks' ? 'active' : ''}" id="tasks-tab">
                    ${this.renderTasksTab(tasks)}
                </div>
                
                <div class="tab-content ${activeTab === 'firmware' ? 'active' : ''}" id="firmware-tab">
                    ${this.renderFirmwareTab()}
                </div>
            </div>
        `;

        this.setHTML('', html);
        this.setupTabs();
        this.setupLabelsEditor();
        this.setupTabRefreshButton();
        // Restore last active tab from view model if available
        const restored = this.viewModel && typeof this.viewModel.get === 'function' ? this.viewModel.get('activeTab') : null;
        if (restored) {
            this.setActiveTab(restored);
        }
        this.setupFirmwareUpload();
    }

    setupTabRefreshButton() {
        const btn = this.findElement('.tab-refresh-btn');
        if (!btn) return;
        this.addEventListener(btn, 'click', async (e) => {
            e.stopPropagation();
            const original = btn.innerHTML;
            btn.disabled = true;
            btn.innerHTML = `
                <svg class="refresh-icon spinning" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                    <path d="M1 4v6h6" />
                    <path d="M23 20v-6h-6" />
                    <path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15" />
                </svg>
            `;

            try {
                const activeTab = (this.viewModel && typeof this.viewModel.get === 'function') ? (this.viewModel.get('activeTab') || 'status') : 'status';
                const nodeIp = (this.viewModel && typeof this.viewModel.get === 'function') ? this.viewModel.get('nodeIp') : null;
                this.suppressLoadingUI = true;

                if (activeTab === 'endpoints' && typeof this.viewModel.loadEndpointsData === 'function') {
                    await this.viewModel.loadEndpointsData();
                } else if (activeTab === 'tasks' && typeof this.viewModel.loadTasksData === 'function') {
                    await this.viewModel.loadTasksData();
                } else if (activeTab === 'labels' && nodeIp && typeof this.viewModel.loadNodeDetails === 'function') {
                    // labels tab: refresh node details to get updated labels
                    await this.viewModel.loadNodeDetails(nodeIp);
                } else if (activeTab === 'status' && typeof this.viewModel.loadMonitoringResources === 'function') {
                    // status tab: load monitoring resources
                    await this.viewModel.loadMonitoringResources();
                } else {
                    // firmware: refresh core node details
                    if (nodeIp && typeof this.viewModel.loadNodeDetails === 'function') {
                        await this.viewModel.loadNodeDetails(nodeIp);
                    }
                }
            } catch (err) {
                logger.error('Tab refresh failed:', err);
            } finally {
                this.suppressLoadingUI = false;
                btn.disabled = false;
                btn.innerHTML = original;
            }
        });
    }

    renderStatusTab(nodeStatus, monitoringResources) {
        let html = '';

        // Add gauges section if monitoring resources are available
        if (monitoringResources) {
            html += this.renderResourceGauges(monitoringResources);
        }

        html += `
            <div class="detail-row">
                <span class="detail-label">Chip ID:</span>
                <span class="detail-value">${nodeStatus.chipId}</span>
            </div>
            <div class="detail-row">
                <span class="detail-label">SDK Version:</span>
                <span class="detail-value">${nodeStatus.sdkVersion}</span>
            </div>
            <div class="detail-row">
                <span class="detail-label">CPU Frequency:</span>
                <span class="detail-value">${nodeStatus.cpuFreqMHz}MHz</span>
            </div>
            <div class="detail-row">
                <span class="detail-label">Flash Size:</span>
                <span class="detail-value">${this.formatFlashSize(nodeStatus.flashChipSize)}</span>
            </div>
        `;

        // Add monitoring resources if available
        if (monitoringResources) {
            html += `
                <div class="monitoring-section">
            `;

            // CPU Usage
            if (monitoringResources.cpu) {
                html += `
                    <div class="detail-row">
                        <span class="detail-label">CPU Usage (Avg):</span>
                        <span class="detail-value">${monitoringResources.cpu.average_usage ? monitoringResources.cpu.average_usage.toFixed(1) + '%' : 'N/A'}</span>
                    </div>
                `;
            }

            // Memory Usage
            if (monitoringResources.memory) {
                const heapUsagePercent = monitoringResources.memory.heap_usage_percent || 0;
                const totalHeap = monitoringResources.memory.total_heap || 0;
                const usedHeap = totalHeap - (monitoringResources.memory.free_heap || 0);
                const usedHeapKB = Math.round(usedHeap / 1024);
                const totalHeapKB = Math.round(totalHeap / 1024);
                
                html += `
                    <div class="detail-row">
                        <span class="detail-label">Heap Usage:</span>
                        <span class="detail-value">${heapUsagePercent.toFixed(1)}% (${usedHeapKB}KB / ${totalHeapKB}KB)</span>
                    </div>
                `;
            }

            // Filesystem Usage
            if (monitoringResources.filesystem) {
                const usedKB = Math.round(monitoringResources.filesystem.used_bytes / 1024);
                const totalKB = Math.round(monitoringResources.filesystem.total_bytes / 1024);
                const usagePercent = monitoringResources.filesystem.total_bytes > 0 
                    ? ((monitoringResources.filesystem.used_bytes / monitoringResources.filesystem.total_bytes) * 100).toFixed(1)
                    : '0.0';
                html += `
                    <div class="detail-row">
                        <span class="detail-label">Filesystem:</span>
                        <span class="detail-value">${usagePercent}% (${usedKB}KB / ${totalKB}KB)</span>
                    </div>
                `;
            }

            // System Information
            if (monitoringResources.system) {
                html += `
                    <div class="detail-row">
                        <span class="detail-label">Uptime:</span>
                        <span class="detail-value">${monitoringResources.system.uptime_formatted || 'N/A'}</span>
                    </div>
                `;
            }

            // Network Information
            if (monitoringResources.network) {
                const uptimeSeconds = monitoringResources.network.uptime_seconds || 0;
                const uptimeHours = Math.floor(uptimeSeconds / 3600);
                const uptimeMinutes = Math.floor((uptimeSeconds % 3600) / 60);
                const uptimeFormatted = `${uptimeHours}h ${uptimeMinutes}m`;
                
                html += `
                    <div class="detail-row">
                        <span class="detail-label">WiFi RSSI:</span>
                        <span class="detail-value">${monitoringResources.network.wifi_rssi || 'N/A'} dBm</span>
                    </div>
                    <div class="detail-row">
                        <span class="detail-label">Network Uptime:</span>
                        <span class="detail-value">${uptimeFormatted}</span>
                    </div>
                `;
            }

            html += `</div>`;
        }

        return html;
    }

    renderResourceGauges(monitoringResources) {
        // Get values with fallbacks and ensure they are numbers
        const cpuUsage = parseFloat(monitoringResources.cpu?.average_usage) || 0;
        const heapUsage = parseFloat(monitoringResources.memory?.heap_usage_percent) || 0;
        const filesystemUsed = parseFloat(monitoringResources.filesystem?.used_bytes) || 0;
        const filesystemTotal = parseFloat(monitoringResources.filesystem?.total_bytes) || 0;
        const filesystemUsage = filesystemTotal > 0 ? (filesystemUsed / filesystemTotal) * 100 : 0;

        // Convert filesystem bytes to KB
        const filesystemUsedKB = Math.round(filesystemUsed / 1024);
        const filesystemTotalKB = Math.round(filesystemTotal / 1024);

        // Helper function to get color class based on percentage
        const getColorClass = (percentage) => {
            const numPercentage = parseFloat(percentage);

            if (numPercentage === 0 || isNaN(numPercentage)) return 'gauge-empty';
            if (numPercentage < 50) return 'gauge-green';
            if (numPercentage < 80) return 'gauge-yellow';
            return 'gauge-red';
        };

        return `
            <div class="resource-gauges">
                <div class="gauge-container">
                    <div class="gauge ${getColorClass(cpuUsage)}" data-percentage="${cpuUsage}" style="--percentage: ${cpuUsage}">
                        <div class="gauge-circle">
                            <div class="gauge-text">
                                <div class="gauge-value">${cpuUsage.toFixed(1)}%</div>
                                <div class="gauge-label">CPU</div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="gauge-container">
                    <div class="gauge ${getColorClass(heapUsage)}" data-percentage="${heapUsage}" style="--percentage: ${heapUsage}">
                        <div class="gauge-circle">
                            <div class="gauge-text">
                                <div class="gauge-value">${heapUsage.toFixed(1)}%</div>
                                <div class="gauge-label">Heap</div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="gauge-container">
                    <div class="gauge ${getColorClass(filesystemUsage)}" data-percentage="${filesystemUsage}" style="--percentage: ${filesystemUsage}">
                        <div class="gauge-circle">
                            <div class="gauge-text">
                                <div class="gauge-value">${filesystemUsage.toFixed(1)}%</div>
                                <div class="gauge-label">Storage</div>
                                <!-- <div class="gauge-detail">${filesystemUsedKB}KB / ${filesystemTotalKB}KB</div> -->
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        `;
    }

    renderLabelsTab(nodeStatus) {
        const labels = nodeStatus?.labels || {};
        const labelsArray = Object.entries(labels);
        
        const labelsHTML = labelsArray.map(([key, value]) => `
            <div class="label-item" data-key="${this.escapeHtml(key)}">
                <div class="label-content">
                    <span class="label-key">${this.escapeHtml(key)}</span>
                    <span class="label-separator">=</span>
                    <span class="label-value">${this.escapeHtml(value)}</span>
                </div>
                <button class="label-remove-btn" data-key="${this.escapeHtml(key)}" title="Remove label">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                        <path d="M18 6L6 18M6 6l12 12"/>
                    </svg>
                </button>
            </div>
        `).join('');
        
        let html = `
            <div class="labels-section">
                <div class="labels-header">
                    <h3>Node Labels</h3>
                    <p class="labels-description">Manage custom labels for this node. Labels help organize and identify nodes in your cluster.</p>
                </div>
                
                <div class="add-label-controls">
                    <input type="text" id="label-key" placeholder="Key" class="label-key-input" maxlength="50">
                    <span class="label-separator">=</span>
                    <input type="text" id="label-value" placeholder="Value" class="label-value-input" maxlength="100">
                    <button class="add-label-btn" type="button">
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
                            <line x1="12" y1="5" x2="12" y2="19"/>
                            <line x1="5" y1="12" x2="19" y2="12"/>
                        </svg>
                        Add Label
                    </button>
                </div>
                
                <div class="labels-list">
                    ${labelsArray.length === 0 ? `
                        <div class="no-labels">
                            <div>No labels configured</div>
                            <div style="font-size: 0.9rem; margin-top: 0.5rem; opacity: 0.7;">Add labels to organize and identify this node</div>
                        </div>
                    ` : labelsHTML}
                </div>
                
                <div class="labels-actions">
                    <button class="save-labels-btn" type="button" disabled>
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
                            <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
                            <polyline points="17,21 17,13 7,13 7,21"/>
                            <polyline points="7,3 7,8 15,8"/>
                        </svg>
                        Save Changes
                    </button>
                </div>
            </div>
        `;
        
        return html;
    }

    renderEndpointsTab(endpoints) {
        if (!endpoints || !Array.isArray(endpoints.endpoints) || endpoints.endpoints.length === 0) {
            return `
                <div class="no-endpoints">
                    <div>No endpoints reported</div>
                    <div style="font-size: 0.9rem; margin-top: 0.5rem; opacity: 0.7;">This node did not return any endpoints</div>
                </div>
            `;
        }

        // Sort endpoints by URI (name), then by method for stable ordering
        const endpointsList = [...endpoints.endpoints].sort((a, b) => {
            const aUri = String(a.uri || '').toLowerCase();
            const bUri = String(b.uri || '').toLowerCase();
            if (aUri < bUri) return -1;
            if (aUri > bUri) return 1;
            const aMethod = String(a.method || '').toLowerCase();
            const bMethod = String(b.method || '').toLowerCase();
            return aMethod.localeCompare(bMethod);
        });

        const total = endpointsList.length;

        // Preserve selection based on a stable key of method+uri if available
        const selectedKey = String(this.getUIState('endpointSelectedKey') || '');
        let selectedIndex = endpointsList.findIndex(ep => `${ep.method} ${ep.uri}` === selectedKey);
        if (selectedIndex === -1) {
            selectedIndex = Number(this.getUIState('endpointSelectedIndex'));
            if (Number.isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= total) {
                selectedIndex = 0;
            }
        }

        // Compute padding for aligned display in dropdown
        const maxMethodLen = endpointsList.reduce((m, ep) => Math.max(m, String(ep.method || '').length), 0);

        const selectorOptions = endpointsList.map((ep, idx) => {
            const method = String(ep.method || '');
            const uri = String(ep.uri || '');
            const padCount = Math.max(1, (maxMethodLen - method.length) + 2);
            const spacer = '&nbsp;'.repeat(padCount);
            return `<option value="${idx}" data-method="${method}" data-uri="${uri}" ${idx === selectedIndex ? 'selected' : ''}>${method}${spacer}${uri}</option>`;
        }).join('');

        const items = endpointsList.map((ep, idx) => {
            const formId = `endpoint-form-${idx}`;
            const resultId = `endpoint-result-${idx}`;
            const params = Array.isArray(ep.params) && ep.params.length > 0
                ? `<div class="endpoint-params">${ep.params.map((p, pidx) => `
                    <label class="endpoint-param" for="${formId}-field-${pidx}">
                        <span class="param-name">${p.name}${p.required ? ' *' : ''}</span>
                        ${this.renderParameterComponent(p, formId, pidx)}
                    </label>
                `).join('')}</div>`
                : '<div class="endpoint-params none">No parameters</div>';
            return `
                <div class="endpoint-item" data-endpoint-index="${idx}" style="display:${idx === selectedIndex ? '' : 'none'};">
                    <div class="endpoint-header">
                        <span class="endpoint-method">${ep.method}</span>
                        <span class="endpoint-uri">${ep.uri}</span>
                        <button class="endpoint-call-btn" data-action="call-endpoint" data-method="${ep.method}" data-uri="${ep.uri}" data-form-id="${formId}" data-result-id="${resultId}">Call</button>
                    </div>
                    <form id="${formId}" class="endpoint-form" onsubmit="return false;">
                        ${params}
                    </form>
                    <div id="${resultId}" class="endpoint-result" style="display:none;"></div>
                </div>
            `;
        }).join('');

        // Attach events after render in setupEndpointsEvents()
        setTimeout(() => this.setupEndpointsEvents(), 0);

        return `
            <div class="endpoint-selector">
                <label class="param-name" for="endpoint-select">Endpoint</label>
                <select id="endpoint-select" class="param-input" style="font-family: monospace;">${selectorOptions}</select>
            </div>
            <div class="endpoints-list">${items}</div>
        `;
    }

    setupEndpointsEvents() {
        const selector = this.findElement('#endpoint-select');
        if (selector) {
            this.addEventListener(selector, 'change', (e) => {
                const selected = Number(e.target.value);
                const items = Array.from(this.findAllElements('.endpoint-item'));
                items.forEach((el, idx) => {
                    el.style.display = (idx === selected) ? '' : 'none';
                });
                this.setUIState('endpointSelectedIndex', selected);
                const opt = e.target.selectedOptions && e.target.selectedOptions[0];
                if (opt) {
                    const method = opt.dataset.method || '';
                    const uri = opt.dataset.uri || '';
                    this.setUIState('endpointSelectedKey', `${method} ${uri}`);
                }
            });
        }

        const buttons = this.findAllElements('.endpoint-call-btn');
        buttons.forEach(btn => {
            this.addEventListener(btn, 'click', async (e) => {
                e.stopPropagation();
                const method = btn.dataset.method || 'GET';
                const uri = btn.dataset.uri || '';
                const formId = btn.dataset.formId;
                const resultId = btn.dataset.resultId;

                const formEl = this.findElement(`#${formId}`);
                const resultEl = this.findElement(`#${resultId}`);
                if (!formEl || !resultEl) return;

                const inputs = Array.from(formEl.querySelectorAll('.param-input'));
                const params = inputs.map(input => {
                    let value = input.value;
                    // For color type, convert hex to RGB integer
                    if (input.dataset.paramType === 'color' && input.type === 'color') {
                        const rgbDisplay = input.parentElement.querySelector('.color-rgb-display');
                        value = rgbDisplay ? rgbDisplay.value : this.hexToRgbInt(input.value);
                    }
                    // For boolean type, convert checkbox checked state to boolean
                    else if (input.dataset.paramType === 'boolean' && input.type === 'checkbox') {
                        value = input.checked;
                    }
                    return {
                        name: input.dataset.paramName,
                        location: input.dataset.paramLocation || 'body',
                        type: input.dataset.paramType || 'string',
                        required: input.dataset.paramRequired === '1',
                        value: value
                    };
                });

                // Required validation
                const missing = params.filter(p => p.required && (p.type === 'boolean' ? false : (!p.value || String(p.value).trim() === '')));
                if (missing.length > 0) {
                    resultEl.style.display = 'block';
                    resultEl.innerHTML = `
                        <div class="endpoint-call-error">
                            <div>❌ Missing required fields: ${missing.map(m => this.escapeHtml(m.name)).join(', ')}</div>
                        </div>
                    `;
                    return;
                }

                // Show loading state
                resultEl.style.display = 'block';
                resultEl.innerHTML = '<div class="loading">Calling endpoint...</div>';

                try {
                    const response = await this.viewModel.callEndpoint(method, uri, params);
                    const pretty = typeof response?.data === 'object' ? JSON.stringify(response.data, null, 2) : String(response?.data ?? '');
                    resultEl.innerHTML = `
                        <div class="endpoint-call-success">
                            <div>${window.icon('success', { width: 14, height: 14 })} Success</div>
                            <pre class="endpoint-result-pre">${this.escapeHtml(pretty)}</pre>
                        </div>
                    `;
                } catch (err) {
                    resultEl.innerHTML = `
                        <div class="endpoint-call-error">
                            <div>${window.icon('error', { width: 14, height: 14 })} Error: ${this.escapeHtml(err.message || 'Request failed')}</div>
                        </div>
                    `;
                }
            });
        });

        // Add event listeners for color pickers
        const colorPickers = this.findAllElements('.color-picker');
        colorPickers.forEach(colorInput => {
            this.addEventListener(colorInput, 'input', (e) => {
                const rgbDisplay = colorInput.parentElement.querySelector('.color-rgb-display');
                if (rgbDisplay) {
                    const hexValue = e.target.value;
                    const rgbInt = this.hexToRgbInt(hexValue);
                    rgbDisplay.value = rgbInt;
                }
            });
        });

        // Update color picker when RGB display is manually changed (if we make it editable later)
        const rgbDisplays = this.findAllElements('.color-rgb-display');
        rgbDisplays.forEach(rgbInput => {
            this.addEventListener(rgbInput, 'input', (e) => {
                const colorPicker = rgbInput.parentElement.querySelector('.color-picker');
                if (colorPicker) {
                    const rgbInt = parseInt(e.target.value) || 0;
                    const hexValue = this.rgbIntToHex(rgbInt);
                    colorPicker.value = hexValue;
                }
            });
        });

        // Add event listeners for range sliders
        const rangeSliders = this.findAllElements('.range-slider');
        rangeSliders.forEach(rangeInput => {
            this.addEventListener(rangeInput, 'input', (e) => {
                const rangeDisplay = rangeInput.parentElement.querySelector('.range-display .range-value');
                if (rangeDisplay) {
                    rangeDisplay.textContent = e.target.value;
                }
            });
        });
    }

    escapeHtml(str) {
        return String(str)
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
    }

    renderTasksTab(tasks) {
        const summary = this.viewModel.get('tasksSummary');
        if (tasks && tasks.length > 0) {
            const summaryHTML = summary ? `
                <div class="tasks-summary">
                    <div class="tasks-summary-left">
                        <div class="summary-icon">${window.icon('file', { width: 16, height: 16 })}</div>
                        <div>
                            <div class="summary-title">Tasks Overview</div>
                            <div class="summary-subtitle">System task management and monitoring</div>
                        </div>
                    </div>
                    <div class="tasks-summary-right">
                        <div class="summary-stat total">
                            <div class="summary-stat-value">${summary.totalTasks ?? tasks.length}</div>
                            <div class="summary-stat-label">Total</div>
                        </div>
                        <div class="summary-stat active">
                            <div class="summary-stat-value">${summary.activeTasks ?? tasks.filter(t => t.running).length}</div>
                            <div class="summary-stat-label">Active</div>
                        </div>
                        <div class="summary-stat stopped">
                            <div class="summary-stat-value">${(summary.totalTasks ?? tasks.length) - (summary.activeTasks ?? tasks.filter(t => t.running).length)}</div>
                            <div class="summary-stat-label">Stopped</div>
                        </div>
                    </div>
                </div>
            ` : '';
            const tasksHTML = tasks.map(task => `
                <div class="task-item">
                    <div class="task-header">
                        <span class="task-name">${task.name || 'Unknown Task'}</span>
                        <span class="task-status ${task.running ? 'running' : 'stopped'}">
                            ${task.running ? window.icon('dotGreen', { width: 10, height: 10 }) + ' Running' : window.icon('dotRed', { width: 10, height: 10 }) + ' Stopped'}
                        </span>
                    </div>
                    <div class="task-details">
                        <span class="task-interval">Interval: ${task.interval}ms</span>
                        <span class="task-enabled">${task.enabled ? window.icon('dotGreen', { width: 10, height: 10 }) + ' Enabled' : window.icon('dotRed', { width: 10, height: 10 }) + ' Disabled'}</span>
                    </div>
                </div>
            `).join('');
            
            return `
                ${summaryHTML}
                ${tasksHTML}
            `;
        } else {
            const total = summary?.totalTasks ?? 0;
            const active = summary?.activeTasks ?? 0;
            return `
                <div class="tasks-summary">
                    <div class="tasks-summary-left">
                        <div class="summary-icon">${window.icon('file', { width: 16, height: 16 })}</div>
                        <div>
                            <div class="summary-title">Tasks Overview</div>
                            <div class="summary-subtitle">${total > 0 ? `Total tasks: ${total}, active: ${active}` : 'This node has no running tasks'}</div>
                        </div>
                    </div>
                    <div class="tasks-summary-right">
                        <div class="summary-stat total">
                            <div class="summary-stat-value">${total}</div>
                            <div class="summary-stat-label">Total</div>
                        </div>
                        <div class="summary-stat active">
                            <div class="summary-stat-value">${active}</div>
                            <div class="summary-stat-label">Active</div>
                        </div>
                        <div class="summary-stat stopped">
                            <div class="summary-stat-value">${total - active}</div>
                            <div class="summary-stat-label">Stopped</div>
                        </div>
                    </div>
                </div>
                <div class="no-tasks">
                    <div>No active tasks found</div>
                    <div style="font-size: 0.9rem; margin-top: 0.5rem; opacity: 0.7;">
                        ${total > 0 ? `Total tasks: ${total}, active: ${active}` : 'This node has no running tasks'}
                    </div>
                </div>
            `;
        }
    }

    renderFirmwareTab() {
        return `
            <div class="firmware-upload">
                <h4>Firmware Update</h4>
                <div class="upload-area">
                    <input type="file" id="firmware-file" accept=".bin,.hex" style="display: none;">
                    <button class="upload-btn" data-action="select-file">
                        ${window.icon('file', { width: 14, height: 14 })} Choose Firmware File
                    </button>
                    <div class="upload-info">Select a .bin or .hex file to upload</div>
                    <div id="upload-status" style="display: none;"></div>
                </div>
            </div>
        `;
    }

    setupTabs() {
        logger.debug('NodeDetailsComponent: Setting up tabs');
        super.setupTabs(this.container, {
            onChange: (tab) => {
                // Persist active tab in the view model for restoration
                if (this.viewModel && typeof this.viewModel.setActiveTab === 'function') {
                    this.viewModel.setActiveTab(tab);
                }
            }
        });
    }

    setupLabelsEditor() {
        // Add label functionality
        const addLabelBtn = this.findElement('.add-label-btn');
        if (addLabelBtn) {
            this.addEventListener(addLabelBtn, 'click', () => this.handleAddLabel());
        }

        // Remove label functionality
        const removeButtons = this.findAllElements('.label-remove-btn');
        removeButtons.forEach(btn => {
            this.addEventListener(btn, 'click', (e) => {
                const key = e.target.closest('.label-remove-btn').dataset.key;
                this.handleRemoveLabel(key);
            });
        });

        // Save labels functionality
        const saveLabelsBtn = this.findElement('.save-labels-btn');
        if (saveLabelsBtn) {
            this.addEventListener(saveLabelsBtn, 'click', () => this.handleSaveLabels());
        }

        // Enter key support for adding labels
        const keyInput = this.findElement('#label-key');
        const valueInput = this.findElement('#label-value');
        
        if (keyInput) {
            this.addEventListener(keyInput, 'keypress', (e) => {
                if (e.key === 'Enter') {
                    valueInput.focus();
                }
            });
        }
        
        if (valueInput) {
            this.addEventListener(valueInput, 'keypress', (e) => {
                if (e.key === 'Enter') {
                    this.handleAddLabel();
                }
            });
        }

        // Input validation
        if (keyInput && valueInput) {
            const validateInputs = () => {
                const hasKey = keyInput.value.trim().length > 0;
                const hasValue = valueInput.value.trim().length > 0;
                addLabelBtn.disabled = !hasKey || !hasValue;
            };

            this.addEventListener(keyInput, 'input', validateInputs);
            this.addEventListener(valueInput, 'input', validateInputs);
        }
    }

    // Update active tab without full re-render
    updateActiveTab(newTab, previousTab = null) {
        this.setActiveTab(newTab);
        logger.debug(`NodeDetailsComponent: Active tab updated to '${newTab}'`);
    }

    setupFirmwareUpload() {
        const uploadBtn = this.findElement('.upload-btn[data-action="select-file"]');
        if (uploadBtn) {
            this.addEventListener(uploadBtn, 'click', (e) => {
                e.stopPropagation();
                const fileInput = this.findElement('#firmware-file');
                if (fileInput) {
                    fileInput.click();
                }
            });
            
            // Set up file input change handler
            const fileInput = this.findElement('#firmware-file');
            if (fileInput) {
                this.addEventListener(fileInput, 'change', async (e) => {
                    e.stopPropagation();
                    const file = e.target.files[0];
                    if (file) {
                        await this.uploadFirmware(file);
                    }
                });
            }
        }
    }

    async uploadFirmware(file) {
        const uploadStatus = this.findElement('#upload-status');
        const uploadBtn = this.findElement('.upload-btn');
        const originalText = uploadBtn.textContent;
        
        try {
            // Show upload status
            uploadStatus.style.display = 'block';
            uploadStatus.innerHTML = `
                    <div class="upload-progress">
                    <div>${window.icon('upload', { width: 14, height: 14 })} Uploading ${this.escapeHtml(file.name)}...</div>
                    <div style="font-size: 0.8rem; opacity: 0.7;">Size: ${(file.size / 1024).toFixed(1)}KB</div>
                </div>
            `;
            
            // Disable upload button
            uploadBtn.disabled = true;
            uploadBtn.textContent = 'Uploading...';
            
            // Get the member IP from the card if available, otherwise fallback to view model state
            const memberCard = this.container.closest('.member-card');
            let memberIp = null;
            if (memberCard && memberCard.dataset && memberCard.dataset.memberIp) {
                memberIp = memberCard.dataset.memberIp;
            } else if (this.viewModel && typeof this.viewModel.get === 'function') {
                memberIp = this.viewModel.get('nodeIp');
            }
            
            if (!memberIp) {
                throw new Error('Could not determine target node IP address');
            }
            
            // Upload firmware
            const result = await this.viewModel.uploadFirmware(file, memberIp);
            
            // Show success
            uploadStatus.innerHTML = `
                <div class="upload-success">
                    <div>${window.icon('success', { width: 14, height: 14 })} Firmware uploaded successfully!</div>
                    <div style="font-size: 0.8rem; margin-top: 0.5rem; opacity: 0.7;">Node: ${memberIp}</div>
                    <div style="font-size: 0.8rem; margin-top: 0.5rem; opacity: 0.7;">Size: ${(file.size / 1024).toFixed(1)}KB</div>
                </div>
            `;
            
            logger.debug('Firmware upload successful:', result);
            
        } catch (error) {
            logger.error('Firmware upload failed:', error);
            
            // Show error
            uploadStatus.innerHTML = `
                <div class="upload-error">
                    <div>${window.icon('error', { width: 14, height: 14 })} Upload failed: ${this.escapeHtml(error.message)}</div>
                </div>
            `;
        } finally {
            // Re-enable upload button
            uploadBtn.disabled = false;
            uploadBtn.textContent = originalText;
            
            // Clear file input
            const fileInput = this.findElement('#firmware-file');
            if (fileInput) {
                fileInput.value = '';
            }
        }
    }
}

window.NodeDetailsComponent = NodeDetailsComponent; 