// Firmware Component
class FirmwareComponent extends Component {
    constructor(container, viewModel, eventBus) {
        super(container, viewModel, eventBus);
        
        logger.debug('FirmwareComponent: Constructor called');
        logger.debug('FirmwareComponent: Container:', container);
        logger.debug('FirmwareComponent: Container ID:', container?.id);
        
        // Initialize overlay dialog
        this.overlayDialog = null;
        
        // Check if the dropdown exists in the container
        if (container) {
            const dropdown = container.querySelector('#specific-node-select');
            logger.debug('FirmwareComponent: Dropdown found in constructor:', !!dropdown);
            if (dropdown) {
                logger.debug('FirmwareComponent: Dropdown tagName:', dropdown.tagName);
                logger.debug('FirmwareComponent: Dropdown id:', dropdown.id);
            }
        }
    }

    setupEventListeners() {
        // Setup global firmware file input
        const globalFirmwareFile = this.findElement('#global-firmware-file');
        if (globalFirmwareFile) {
            this.addEventListener(globalFirmwareFile, 'change', this.handleFileSelect.bind(this));
        }
        
        // Setup target selection
        const targetRadios = this.findAllElements('input[name="target-type"]');
        targetRadios.forEach(radio => {
            this.addEventListener(radio, 'change', this.handleTargetChange.bind(this));
        });
        
        // Setup specific node select change handler
        const specificNodeSelect = this.findElement('#specific-node-select');
        logger.debug('FirmwareComponent: setupEventListeners - specificNodeSelect found:', !!specificNodeSelect);
        if (specificNodeSelect) {
            logger.debug('FirmwareComponent: specificNodeSelect element:', specificNodeSelect);
            logger.debug('FirmwareComponent: specificNodeSelect tagName:', specificNodeSelect.tagName);
            logger.debug('FirmwareComponent: specificNodeSelect id:', specificNodeSelect.id);
            
            // Store the bound handler as an instance property
            this._boundNodeSelectHandler = this.handleNodeSelect.bind(this);
            this.addEventListener(specificNodeSelect, 'change', this._boundNodeSelectHandler);
            logger.debug('FirmwareComponent: Event listener added to specificNodeSelect');
        } else {
            logger.warn('FirmwareComponent: specificNodeSelect element not found during setupEventListeners');
        }
        
        // Setup label select change handler (single-select add-to-chips)
        const labelSelect = this.findElement('#label-select');
        if (labelSelect) {
            this._boundLabelSelectHandler = (e) => {
                const value = e.target.value;
                if (!value) return;
                const current = this.viewModel.get('selectedLabels') || [];
                if (!current.includes(value)) {
                    this.viewModel.setSelectedLabels([...current, value]);
                }
                // Reset select back to placeholder
                e.target.value = '';
                this.renderSelectedLabelChips();
                this.updateAffectedNodesPreview();
                this.updateDeployButton();
            };
            this.addEventListener(labelSelect, 'change', this._boundLabelSelectHandler);
        }
        
        // Setup deploy button
        const deployBtn = this.findElement('#deploy-btn');
        if (deployBtn) {
            this.addEventListener(deployBtn, 'click', this.handleDeploy.bind(this));
        }
    }

    setupViewModelListeners() {
        this.subscribeToProperty('selectedFile', () => {
            this.updateFileInfo();
            this.updateDeployButton();
        });
        this.subscribeToProperty('targetType', () => {
            this.updateTargetVisibility();
            this.updateDeployButton();
            this.updateAffectedNodesPreview();
        });
        this.subscribeToProperty('specificNode', this.updateDeployButton.bind(this));
        this.subscribeToProperty('availableNodes', () => {
            this.populateNodeSelect();
            this.populateLabelSelect();
            this.updateDeployButton();
            this.updateAffectedNodesPreview();
        });
        this.subscribeToProperty('uploadProgress', this.updateUploadProgress.bind(this));
        this.subscribeToProperty('uploadResults', this.updateUploadResults.bind(this));
        this.subscribeToProperty('isUploading', this.updateUploadState.bind(this));
        this.subscribeToProperty('selectedLabels', () => {
            this.populateLabelSelect();
            this.updateAffectedNodesPreview();
            this.updateDeployButton();
        });
    }

    mount() {
        super.mount();
        
        logger.debug('FirmwareComponent: Mounting...');
        
        // Initialize overlay dialog
        this.initializeOverlayDialog();
        
        // Check if the dropdown exists when mounted
        const dropdown = this.findElement('#specific-node-select');
        logger.debug('FirmwareComponent: Mount - dropdown found:', !!dropdown);
        if (dropdown) {
            logger.debug('FirmwareComponent: Mount - dropdown tagName:', dropdown.tagName);
            logger.debug('FirmwareComponent: Mount - dropdown id:', dropdown.id);
            logger.debug('FirmwareComponent: Mount - dropdown innerHTML:', dropdown.innerHTML);
        }
        
        // Initialize target visibility and label list on first mount
        try {
            this.updateTargetVisibility();
            this.populateLabelSelect();
            this.updateAffectedNodesPreview();
        } catch (e) {
            logger.warn('FirmwareComponent: Initialization after mount failed:', e);
        }
        
        logger.debug('FirmwareComponent: Mounted successfully');
    }

    render() {
        // Initial render is handled by the HTML template
        this.updateDeployButton();
    }

    initializeOverlayDialog() {
        // Create overlay container if it doesn't exist
        let overlayContainer = document.getElementById('firmware-overlay-dialog');
        if (!overlayContainer) {
            overlayContainer = document.createElement('div');
            overlayContainer.id = 'firmware-overlay-dialog';
            overlayContainer.className = 'overlay-dialog';
            document.body.appendChild(overlayContainer);
        }

        // Create and initialize the overlay dialog component
        if (!this.overlayDialog) {
            const overlayVM = new ViewModel();
            this.overlayDialog = new OverlayDialogComponent(overlayContainer, overlayVM, this.eventBus);
            this.overlayDialog.mount();
        }
    }

    handleFileSelect(event) {
        const file = event.target.files[0];
        this.viewModel.setSelectedFile(file);
    }

    handleTargetChange(event) {
        const targetType = event.target.value;
        this.viewModel.setTargetType(targetType);
    }

    handleNodeSelect(event) {
        const nodeIp = event.target.value;
        logger.debug('FirmwareComponent: handleNodeSelect called with nodeIp:', nodeIp);
        logger.debug('Event:', event);
        logger.debug('Event target:', event.target);
        logger.debug('Event target value:', event.target.value);
        
        this.viewModel.setSpecificNode(nodeIp);
        
        // Also update the deploy button state
        this.updateDeployButton();
    }

    async handleDeploy() {
        const file = this.viewModel.get('selectedFile');
        const targetType = this.viewModel.get('targetType');
        const specificNode = this.viewModel.get('specificNode');
        
        if (!file) {
            this.showConfirmationDialog({
                title: 'No File Selected',
                message: 'Please select a firmware file first.',
                confirmText: 'OK',
                cancelText: null,
                onConfirm: () => {},
                onCancel: null
            });
            return;
        }
        
        if (targetType === 'specific' && !specificNode) {
            this.showConfirmationDialog({
                title: 'No Node Selected',
                message: 'Please select a specific node to update.',
                confirmText: 'OK',
                cancelText: null,
                onConfirm: () => {},
                onCancel: null
            });
            return;
        }
        
        // Show confirmation dialog for deployment
        this.showDeploymentConfirmation(file, targetType, specificNode);
    }

    showConfirmationDialog(options) {
        if (!this.overlayDialog) {
            this.initializeOverlayDialog();
        }
        
        this.overlayDialog.show(options);
    }

    showDeploymentConfirmation(file, targetType, specificNode) {
        let title, message;
        
        if (targetType === 'all') {
            const nodes = this.viewModel.get('availableNodes') || [];
            title = 'Deploy to All Nodes';
            message = `Upload firmware "${file.name}" to all ${nodes.length} nodes?<br><br>This will update:<br>${nodes.map(n => `• ${n.hostname || n.ip}`).join('<br>')}`;
        } else if (targetType === 'specific') {
            title = 'Deploy to Specific Node';
            message = `Upload firmware "${file.name}" to node ${specificNode}?`;
        } else if (targetType === 'labels') {
            const nodes = this.viewModel.getAffectedNodesByLabels();
            const labels = this.viewModel.get('selectedLabels') || [];
            title = 'Deploy to Labeled Nodes';
            message = `Upload firmware "${file.name}" to ${nodes.length} node(s) matching labels (${labels.join(', ')})?<br><br>This will update:<br>${nodes.map(n => `• ${n.hostname || n.ip}`).join('<br>')}`;
        }
        
        this.showConfirmationDialog({
            title: title,
            message: message,
            confirmText: 'Deploy',
            cancelText: 'Cancel',
            onConfirm: () => this.performDeployment(file, targetType, specificNode),
            onCancel: () => {}
        });
    }

    async performDeployment(file, targetType, specificNode) {
        try {
            this.viewModel.startUpload();
            
            if (targetType === 'all') {
                await this.uploadToAllNodes(file);
            } else if (targetType === 'specific') {
                await this.uploadToSpecificNode(file, specificNode);
            } else if (targetType === 'labels') {
                await this.uploadToLabelFilteredNodes(file);
            }
            
            // Reset interface after successful upload
            this.viewModel.resetUploadState();
            
        } catch (error) {
            logger.error('Firmware deployment failed:', error);
            this.showConfirmationDialog({
                title: 'Deployment Failed',
                message: `Deployment failed: ${error.message}`,
                confirmText: 'OK',
                cancelText: null,
                onConfirm: () => {},
                onCancel: null
            });
        } finally {
            this.viewModel.completeUpload();
        }
    }

    async uploadToAllNodes(file) {
        try {
            // Get current cluster members
            const response = await window.apiClient.getClusterMembers();
            const nodes = response.members || [];
            
            if (nodes.length === 0) {
                this.showConfirmationDialog({
                    title: 'No Nodes Available',
                    message: 'No nodes available for firmware update.',
                    confirmText: 'OK',
                    cancelText: null,
                    onConfirm: () => {},
                    onCancel: null
                });
                return;
            }
            
            // Show upload progress area
            this.showUploadProgress(file, nodes);
            
            // Start batch upload
            const results = await this.performBatchUpload(file, nodes);
            
            // Display results
            this.displayUploadResults(results);
            
        } catch (error) {
            logger.error('Failed to upload firmware to all nodes:', error);
            throw error;
        }
    }

    async uploadToSpecificNode(file, nodeIp) {
        try {
            // Show upload progress area
            this.showUploadProgress(file, [{ ip: nodeIp, hostname: nodeIp }]);
            
            // Update progress to show starting
            this.updateNodeProgress(1, 1, nodeIp, 'Uploading...');
            
            // Perform single node upload
            const result = await this.performSingleUpload(file, nodeIp);
            
            // Update progress to show completion
            this.updateNodeProgress(1, 1, nodeIp, 'Completed');
            this.updateOverallProgress(1, 1);
            
            // Display results
            this.displayUploadResults([result]);
            
        } catch (error) {
            logger.error(`Failed to upload firmware to node ${nodeIp}:`, error);
            
            // Update progress to show failure
            this.updateNodeProgress(1, 1, nodeIp, 'Failed');
            this.updateOverallProgress(0, 1);
            
            // Display error results
            const errorResult = {
                nodeIp: nodeIp,
                hostname: nodeIp,
                success: false,
                error: error.message,
                timestamp: new Date().toISOString()
            };
            this.displayUploadResults([errorResult]);
            
            throw error;
        }
    }

    async uploadToLabelFilteredNodes(file) {
        try {
            const nodes = this.viewModel.getAffectedNodesByLabels();
            if (!nodes || nodes.length === 0) {
                this.showConfirmationDialog({
                    title: 'No Matching Nodes',
                    message: 'No nodes match the selected labels.',
                    confirmText: 'OK',
                    cancelText: null,
                    onConfirm: () => {},
                    onCancel: null
                });
                return;
            }
            
            // Show upload progress area
            this.showUploadProgress(file, nodes);
            
            // Start batch upload
            const results = await this.performBatchUpload(file, nodes);
            
            // Display results
            this.displayUploadResults(results);
        } catch (error) {
            logger.error('Failed to upload firmware to label-filtered nodes:', error);
            throw error;
        }
    }

    async performBatchUpload(file, nodes) {
        const results = [];
        const totalNodes = nodes.length;
        let successfulUploads = 0;
        
        for (let i = 0; i < nodes.length; i++) {
            const node = nodes[i];
            const nodeIp = node.ip;
            
            try {
                // Update progress
                this.updateNodeProgress(i + 1, totalNodes, nodeIp, 'Uploading...');
                
                // Upload to this node
                const result = await this.performSingleUpload(file, nodeIp);
                results.push(result);
                successfulUploads++;
                
                // Update progress
                this.updateNodeProgress(i + 1, totalNodes, nodeIp, 'Completed');
                this.updateOverallProgress(successfulUploads, totalNodes);
                
            } catch (error) {
                logger.error(`Failed to upload to node ${nodeIp}:`, error);
                const errorResult = {
                    nodeIp: nodeIp,
                    hostname: node.hostname || nodeIp,
                    success: false,
                    error: error.message,
                    timestamp: new Date().toISOString()
                };
                results.push(errorResult);
                
                // Update progress
                this.updateNodeProgress(i + 1, totalNodes, nodeIp, 'Failed');
                this.updateOverallProgress(successfulUploads, totalNodes);
            }
            
            // Small delay between uploads
            if (i < nodes.length - 1) {
                await new Promise(resolve => setTimeout(resolve, 1000));
            }
        }
        
        return results;
    }

    async performSingleUpload(file, nodeIp) {
        try {
            const result = await window.apiClient.uploadFirmware(file, nodeIp);
            
            return {
                nodeIp: nodeIp,
                hostname: nodeIp,
                success: true,
                result: result,
                timestamp: new Date().toISOString()
            };
            
        } catch (error) {
            throw new Error(`Upload to ${nodeIp} failed: ${error.message}`);
        }
    }

    showUploadProgress(file, nodes) {
        const container = this.findElement('#firmware-nodes-list');
        
        const progressHTML = `
            <div class="firmware-upload-progress" id="firmware-upload-progress">
                <div class="progress-header">
                    <h3>
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16" style="margin-right:6px; vertical-align: -2px;">
                            <path d="M12 16V4"/>
                            <path d="M8 8l4-4 4 4"/>
                            <path d="M20 16v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2"/>
                        </svg>
                        Firmware Upload Progress
                    </h3>
                    <div class="progress-info">
                        <span>File: ${file.name}</span>
                        <span>Size: ${(file.size / 1024).toFixed(1)}KB</span>
                        <span>Targets: ${nodes.length} node(s)</span>
                    </div>
                    <div class="overall-progress">
                        <div class="progress-bar-container">
                            <div class="progress-bar" id="overall-progress-bar" style="width: 0%; background-color: #fbbf24;"></div>
                        </div>
                        <span class="progress-text">0/${nodes.length} Successful (0%)</span>
                    </div>
                    <div class="progress-summary" id="progress-summary">
                        <span>Status: Preparing upload...</span>
                    </div>
                </div>
                <div class="progress-list" id="progress-list">
                    ${nodes.map(node => `
                        <div class="progress-item" data-node-ip="${node.ip}">
                            <div class="progress-node-info">
                                <span class="node-name">${node.hostname || node.ip}</span>
                                <span class="node-ip">${node.ip}</span>
                            </div>
                            <div class="progress-status">Pending...</div>
                            <div class="progress-time" id="time-${node.ip}"></div>
                        </div>
                    `).join('')}
                </div>
            </div>
        `;
        
        container.innerHTML = progressHTML;
        
        // Initialize progress for single-node uploads
        if (nodes.length === 1) {
            const node = nodes[0];
            this.updateNodeProgress(1, 1, node.ip, 'Pending...');
        }
    }

    updateNodeProgress(current, total, nodeIp, status) {
        const progressItem = this.findElement(`[data-node-ip="${nodeIp}"]`);
        if (progressItem) {
            const statusElement = progressItem.querySelector('.progress-status');
            const timeElement = progressItem.querySelector('.progress-time');
            
            if (statusElement) {
                statusElement.textContent = status;
                
                // Add status-specific styling
                statusElement.className = 'progress-status';
                if (status === 'Completed') {
                    statusElement.classList.add('success');
                    if (timeElement) {
                        timeElement.textContent = new Date().toLocaleTimeString();
                    }
                } else if (status === 'Failed') {
                    statusElement.classList.add('error');
                    if (timeElement) {
                        timeElement.textContent = new Date().toLocaleTimeString();
                    }
                } else if (status === 'Uploading...') {
                    statusElement.classList.add('uploading');
                    if (timeElement) {
                        timeElement.textContent = 'Started: ' + new Date().toLocaleTimeString();
                    }
                }
            }
        }
    }

    updateOverallProgress(successfulUploads, totalNodes) {
        const progressBar = this.findElement('#overall-progress-bar');
        const progressText = this.findElement('.progress-text');
        
        if (progressBar && progressText) {
            const successPercentage = Math.round((successfulUploads / totalNodes) * 100);
            progressBar.style.width = `${successPercentage}%`;
            progressText.textContent = `${successfulUploads}/${totalNodes} Successful (${successPercentage}%)`;
            
            // Update progress bar color based on completion
            if (successPercentage === 100) {
                progressBar.style.backgroundColor = '#4ade80';
            } else if (successPercentage > 50) {
                progressBar.style.backgroundColor = '#60a5fa';
            } else {
                progressBar.style.backgroundColor = '#fbbf24';
            }
            
            // Update progress summary for single-node uploads
            const progressSummary = this.findElement('#progress-summary');
            if (progressSummary && totalNodes === 1) {
                if (successfulUploads === 1) {
                    progressSummary.innerHTML = '<span>Status: Upload completed successfully</span>';
                } else if (successfulUploads === 0) {
                    progressSummary.innerHTML = '<span>Status: Upload failed</span>';
                }
            }
        }
    }

    displayUploadResults(results) {
        const progressHeader = this.findElement('.progress-header h3');
        const progressSummary = this.findElement('#progress-summary');
        
        if (progressHeader && progressSummary) {
            const successCount = results.filter(r => r.success).length;
            const totalCount = results.length;
            const successRate = Math.round((successCount / totalCount) * 100);
            
            if (totalCount === 1) {
                // Single node upload
                if (successCount === 1) {
                    progressHeader.textContent = `Firmware Upload Complete`;
                    progressSummary.innerHTML = `<span>${window.icon('success', { width: 14, height: 14 })} Upload to ${results[0].hostname || results[0].nodeIp} completed successfully at ${new Date().toLocaleTimeString()}</span>`;
                } else {
                    progressHeader.textContent = `Firmware Upload Failed`;
                    progressSummary.innerHTML = `<span>${window.icon('error', { width: 14, height: 14 })} Upload to ${results[0].hostname || results[0].nodeIp} failed at ${new Date().toLocaleTimeString()}</span>`;
                }
            } else if (successCount === totalCount) {
                // Multi-node upload - all successful
                progressHeader.textContent = `Firmware Upload Complete (${successCount}/${totalCount} Successful)`;
                progressSummary.innerHTML = `<span>${window.icon('success', { width: 14, height: 14 })} All uploads completed successfully at ${new Date().toLocaleTimeString()}</span>`;
            } else {
                // Multi-node upload - some failed
                progressHeader.textContent = `Firmware Upload Results (${successCount}/${totalCount} Successful)`;
                progressSummary.innerHTML = `<span>${window.icon('warning', { width: 14, height: 14 })} Upload completed with ${totalCount - successCount} failure(s) at ${new Date().toLocaleTimeString()}</span>`;
            }
        }
    }

    updateFileInfo() {
        const file = this.viewModel.get('selectedFile');
        const fileInfo = this.findElement('#file-info');
        const deployBtn = this.findElement('#deploy-btn');
        
        if (file) {
            fileInfo.textContent = `${file.name} (${(file.size / 1024).toFixed(1)}KB)`;
            fileInfo.classList.add('has-file');
        } else {
            fileInfo.textContent = 'No file selected';
            fileInfo.classList.remove('has-file');
        }
        
        this.updateDeployButton();
    }

    updateTargetVisibility() {
        const targetType = this.viewModel.get('targetType');
        const specificNodeSelect = this.findElement('#specific-node-select');
        const labelSelect = this.findElement('#label-select');
        
        logger.debug('FirmwareComponent: updateTargetVisibility called with targetType:', targetType);
        
        if (targetType === 'specific') {
            if (specificNodeSelect) { specificNodeSelect.style.display = 'inline-block'; }
            if (labelSelect) { labelSelect.style.display = 'none'; }
            this.populateNodeSelect();
        } else if (targetType === 'labels') {
            if (specificNodeSelect) { specificNodeSelect.style.display = 'none'; }
            if (labelSelect) {
                labelSelect.style.display = 'inline-block';
                this.populateLabelSelect();
            }
        } else {
            if (specificNodeSelect) { specificNodeSelect.style.display = 'none'; }
            if (labelSelect) { labelSelect.style.display = 'none'; }
        }
        this.updateDeployButton();
    }

    // Note: handleNodeSelect is already defined above and handles the actual node selection
    // This duplicate method was causing the issue - removing it

    updateDeployButton() {
        const deployBtn = this.findElement('#deploy-btn');
        if (deployBtn) {
            deployBtn.disabled = !this.viewModel.isDeployEnabled();
        }
    }

    populateNodeSelect() {
        const select = this.findElement('#specific-node-select');
        if (!select) {
            logger.warn('FirmwareComponent: populateNodeSelect - select element not found');
            return;
        }
        
        if (select.tagName !== 'SELECT') {
            logger.warn('FirmwareComponent: populateNodeSelect - element is not a SELECT:', select.tagName);
            return;
        }
        
        logger.debug('FirmwareComponent: populateNodeSelect called');
        logger.debug('FirmwareComponent: Select element:', select);
        logger.debug('FirmwareComponent: Available nodes:', this.viewModel.get('availableNodes'));
        
        // Clear existing options
        select.innerHTML = '<option value="">Select a node...</option>';
        
        // Get available nodes from the view model
        const availableNodes = this.viewModel.get('availableNodes');
        
        if (!availableNodes || availableNodes.length === 0) {
            // No nodes available
            const option = document.createElement('option');
            option.value = "";
            option.textContent = "No nodes available";
            option.disabled = true;
            select.appendChild(option);
            return;
        }
        
        availableNodes.forEach(node => {
            const option = document.createElement('option');
            option.value = node.ip;
            option.textContent = `${node.hostname} (${node.ip})`;
            select.appendChild(option);
        });
        
        // Ensure event listener is still bound after repopulating
        this.ensureNodeSelectListener(select);
        
        logger.debug('FirmwareComponent: Node select populated with', availableNodes.length, 'nodes');
    }

    // Ensure the node select change listener is properly bound
    ensureNodeSelectListener(select) {
        if (!select) return;
        
        // Store the bound handler as an instance property to avoid binding issues
        if (!this._boundNodeSelectHandler) {
            this._boundNodeSelectHandler = this.handleNodeSelect.bind(this);
        }
        
        // Remove any existing listeners and add the bound one
        select.removeEventListener('change', this._boundNodeSelectHandler);
        select.addEventListener('change', this._boundNodeSelectHandler);
        
        logger.debug('FirmwareComponent: Node select event listener ensured');
    }

    updateUploadProgress() {
        // This will be implemented when we add upload progress tracking
    }

    updateUploadResults() {
        // This will be implemented when we add upload results display
    }

    updateUploadState() {
        const isUploading = this.viewModel.get('isUploading');
        const deployBtn = this.findElement('#deploy-btn');
        
        if (deployBtn) {
            deployBtn.disabled = isUploading;
            if (isUploading) {
                deployBtn.classList.add('loading');
                deployBtn.textContent = '⏳ Deploying...';
            } else {
                deployBtn.classList.remove('loading');
                deployBtn.textContent = '🚀 Deploy';
            }
        }
        
        this.updateDeployButton();
    }

    populateLabelSelect() {
        const select = this.findElement('#label-select');
        if (!select) return;
        const labels = this.viewModel.get('availableLabels') || [];
        const selected = new Set(this.viewModel.get('selectedLabels') || []);
        const options = ['<option value="">Select a label...</option>']
            .concat(labels.filter(l => !selected.has(l)).map(l => `<option value="${l}">${l}</option>`));
        select.innerHTML = options.join('');
        // Ensure change listener remains bound
        if (this._boundLabelSelectHandler) {
            select.removeEventListener('change', this._boundLabelSelectHandler);
            select.addEventListener('change', this._boundLabelSelectHandler);
        }
        this.renderSelectedLabelChips();
    }

    renderSelectedLabelChips() {
        const container = this.findElement('#selected-labels-container');
        if (!container) return;
        const selected = this.viewModel.get('selectedLabels') || [];
        if (selected.length === 0) {
            container.innerHTML = '';
            return;
        }
        container.innerHTML = selected.map(l => `
            <span class="label-chip removable" data-label="${l}">
                ${l}
                <button class="chip-remove" data-label="${l}" title="Remove">×</button>
            </span>
        `).join('');
        Array.from(container.querySelectorAll('.chip-remove')).forEach(btn => {
            this.addEventListener(btn, 'click', (e) => {
                e.stopPropagation();
                const label = btn.getAttribute('data-label');
                const current = this.viewModel.get('selectedLabels') || [];
                this.viewModel.setSelectedLabels(current.filter(x => x !== label));
                this.populateLabelSelect();
                this.updateAffectedNodesPreview();
                this.updateDeployButton();
            });
        });
    }

    updateAffectedNodesPreview() {
        const container = this.findElement('#firmware-nodes-list');
        if (!container) return;
        if (this.viewModel.get('targetType') !== 'labels') {
            container.innerHTML = '';
            return;
        }
        const nodes = this.viewModel.getAffectedNodesByLabels();
        if (!nodes.length) {
            container.innerHTML = `<div class="empty-state"><div>No nodes match the selected labels</div></div>`;
            return;
        }
        const html = `
            <div class="affected-nodes">
                <div class="progress-header"><h3>Affected Nodes (${nodes.length})</h3></div>
                <div class="progress-list">
                    ${nodes.map(n => `
                        <div class="progress-item" data-node-ip="${n.ip}">
                            <div class="progress-node-info"><span class="node-name">${n.hostname || n.ip}</span><span class="node-ip">${n.ip}</span></div>
                        </div>
                    `).join('')}
                </div>
            </div>`;
        container.innerHTML = html;
    }
}

window.FirmwareComponent = FirmwareComponent; 