File vm-module.js of Package PersistenceOS

/**
 * PersistenceOS VM Management Module
 * Handles virtual machine lifecycle operations, monitoring, and management
 * 
 * Depends on: core-utils.js, auth-module.js
 */

// =============================================================================
// VM STATE MANAGEMENT
// =============================================================================

const vmState = {
    virtualMachines: [],
    vmLoading: false,
    vmActionLoading: {},
    refreshInterval: null,
    lastUpdate: null
};

// =============================================================================
// VM DATA FUNCTIONS
// =============================================================================

/**
 * Refresh VM data from API
 * @returns {Promise<void>}
 */
async function refreshVMs() {
    vmState.vmLoading = true;
    console.log('🔄 Refreshing VM data...');
    
    try {
        const data = await PersistenceCore.apiGet('/vms/');
        console.log('✅ VM data loaded:', data);
        
        // Transform API data to match UI format
        vmState.virtualMachines = data.vms.map(vm => ({
            id: vm.id || vm.name,
            name: vm.name,
            status: vm.status || 'unknown',
            cpu: vm.cpu || vm.vcpus || 2,
            memory: vm.memory || (vm.memory_mb ? Math.round(vm.memory_mb / 1024) : 4),
            storage: vm.storage || vm.disk_gb || 40,
            cpuUsage: vm.cpu_usage || Math.floor(Math.random() * 100),
            memoryUsage: vm.memory_usage || Math.floor(Math.random() * 100),
            uptime: vm.uptime || '0h 0m',
            created: vm.created || new Date().toISOString()
        }));
        
        // Enhanced user feedback
        const vmCount = data.vms?.length || 0;
        const runningCount = data.vms?.filter(vm => vm.status === 'running').length || 0;
        const stoppedCount = data.vms?.filter(vm => vm.status === 'stopped').length || 0;
        
        console.log(`📊 VM Summary: ${vmCount} total, ${runningCount} running, ${stoppedCount} stopped`);
        
        if (vmCount === 0) {
            PersistenceCore.showNotification('â„šī¸ No virtual machines found. Create your first VM to get started!', 'info');
        } else {
            PersistenceCore.showNotification(`✅ Found ${vmCount} VMs (${runningCount} running, ${stoppedCount} stopped)`, 'success');
        }
        
        vmState.lastUpdate = new Date();
        
        // Trigger custom event for Vue.js reactivity
        window.dispatchEvent(new CustomEvent('vm-data-updated', {
            detail: { vms: vmState.virtualMachines, stats: getVMStats() }
        }));
        
    } catch (error) {
        console.error('❌ Error refreshing VMs:', error);
        PersistenceCore.showNotification('❌ Error refreshing VM data. Check system connectivity.', 'error');
    } finally {
        vmState.vmLoading = false;
    }
}

/**
 * Get VM statistics
 * @returns {object}
 */
function getVMStats() {
    const running = vmState.virtualMachines.filter(vm => vm.status === 'running').length;
    const stopped = vmState.virtualMachines.filter(vm => vm.status === 'stopped').length;
    const total = vmState.virtualMachines.length;
    const avgCpu = total > 0 ?
        Math.round(vmState.virtualMachines.reduce((sum, vm) => sum + (vm.cpuUsage || 0), 0) / total) : 0;
    
    return { running, stopped, total, avgCpu };
}

// =============================================================================
// VM LIFECYCLE OPERATIONS
// =============================================================================

/**
 * Perform VM action (start, stop, restart, delete)
 * @param {string} action - Action to perform
 * @param {string} vmId - VM ID
 * @param {string} vmName - VM name for user feedback
 * @returns {Promise<void>}
 */
async function performVMAction(action, vmId, vmName) {
    console.log(`đŸŽ¯ Performing ${action} on VM: ${vmName} (${vmId})`);
    
    // Enhanced action-specific messaging
    const actionMessages = {
        start: { loading: `â–ļī¸ Starting VM "${vmName}"...`, success: `✅ VM "${vmName}" started successfully!` },
        stop: { loading: `âšī¸ Stopping VM "${vmName}"...`, success: `✅ VM "${vmName}" stopped successfully!` },
        restart: { loading: `🔄 Restarting VM "${vmName}"...`, success: `✅ VM "${vmName}" restarted successfully!` },
        delete: { loading: `đŸ—‘ī¸ Deleting VM "${vmName}"...`, success: `✅ VM "${vmName}" deleted successfully!` }
    };
    
    const messages = actionMessages[action] || {
        loading: `🔄 ${action}ing VM "${vmName}"...`,
        success: `✅ VM "${vmName}" ${action} completed!`
    };
    
    // Show loading notification
    PersistenceCore.showNotification(messages.loading, 'info');
    
    // Set loading state for this specific VM
    vmState.vmActionLoading = { ...vmState.vmActionLoading, [vmId]: true };
    
    try {
        // Use DELETE method for delete action, POST for others
        const method = action === 'delete' ? 'DELETE' : 'POST';
        const endpoint = action === 'delete' ? `/vms/${vmId}` : `/vms/${vmId}/${action}`;
        
        const response = await PersistenceCore.makeApiRequest(endpoint, { method });
        
        if (response.ok) {
            const result = await response.json();
            console.log(`✅ ${action} successful:`, result);
            
            // Show enhanced success notification
            PersistenceCore.showNotification(messages.success, 'success');
            
            // Enhanced refresh timing based on action
            const refreshDelay = action === 'restart' ? 3000 : action === 'delete' ? 1000 : 2000;
            setTimeout(() => {
                refreshVMs();
            }, refreshDelay);
        } else {
            const errorData = await response.json().catch(() => ({}));
            const errorMessage = errorData.detail || errorData.message || `${action} failed with status ${response.status}`;
            throw new Error(errorMessage);
        }
    } catch (error) {
        console.error(`❌ ${action} error:`, error);
        PersistenceCore.showNotification(`❌ Failed to ${action} VM "${vmName}": ${error.message}`, 'error');
    } finally {
        // Clear loading state for this VM
        const newLoading = { ...vmState.vmActionLoading };
        delete newLoading[vmId];
        vmState.vmActionLoading = newLoading;
    }
}

/**
 * Delete VM with confirmation
 * @param {string} vmId - VM ID
 * @param {string} vmName - VM name
 * @returns {Promise<void>}
 */
async function deleteVM(vmId, vmName) {
    const confirmed = confirm(`Are you sure you want to delete VM "${vmName}"? This action cannot be undone.`);
    if (confirmed) {
        await performVMAction('delete', vmId, vmName);
    }
}

// =============================================================================
// VM CREATION
// =============================================================================

/**
 * Create new VM with enhanced modal interface
 * @returns {Promise<void>}
 */
async function createVM() {
    console.log('➕ Opening Create VM dialog');

    // Check if libvirt is available first
    try {
        const healthResponse = await PersistenceCore.makeApiRequest('/vms/health/check');
        const healthData = await healthResponse.json();

        if (!healthData.libvirt_available) {
            PersistenceCore.showNotification('âš ī¸ Virtualization not available. Please check libvirt service.', 'warning');
            return;
        }
    } catch (error) {
        console.warn('Could not check VM health:', error);
    }

    // Create enhanced VM creation modal (implementation would be extensive)
    // For now, show a placeholder notification
    PersistenceCore.showNotification('🚧 VM Creation modal - Feature in development', 'info');

    // TODO: Implement full VM creation modal with:
    // - OS selection
    // - Resource configuration
    // - Storage pool selection
    // - Network configuration
    // - Advanced settings
}

// =============================================================================
// VM CONSOLE AND SETTINGS
// =============================================================================

/**
 * Open VM console
 * @param {string} vmId - VM ID
 * @param {string} vmName - VM name
 */
function openVMConsole(vmId, vmName) {
    console.log(`đŸ–Ĩī¸ Opening console for VM: ${vmName} (${vmId})`);
    
    // Create console window
    const consoleUrl = `/api/vms/${vmId}/console`;
    const consoleWindow = window.open(consoleUrl, `vm-console-${vmId}`, 
        'width=800,height=600,scrollbars=yes,resizable=yes');
    
    if (consoleWindow) {
        PersistenceCore.showNotification(`Opening console for VM "${vmName}"`, 'info');
    } else {
        PersistenceCore.showNotification('Failed to open console window. Check popup blocker.', 'error');
    }
}

/**
 * Show VM settings modal
 * @param {string} vmId - VM ID
 * @param {string} vmName - VM name
 */
function showVMSettings(vmId, vmName) {
    console.log(`âš™ī¸ Opening settings for VM: ${vmName} (${vmId})`);
    
    // Find VM data
    const vm = vmState.virtualMachines.find(v => v.id === vmId);
    if (!vm) {
        PersistenceCore.showNotification('VM not found', 'error');
        return;
    }
    
    // Create settings modal
    const modalHtml = `
        <div id="vmSettingsModal" class="modal" style="display: block;">
            <div class="modal-content" style="max-width: 600px;">
                <div class="modal-header">
                    <h3><i class="fas fa-cog"></i> VM Settings - ${vmName}</h3>
                    <button class="close-btn" onclick="closeVMSettingsModal()">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
                <div class="modal-body">
                    <div class="settings-section">
                        <h4>Basic Information</h4>
                        <p><strong>Name:</strong> ${vm.name}</p>
                        <p><strong>ID:</strong> ${vm.id}</p>
                        <p><strong>Status:</strong> ${vm.status}</p>
                        <p><strong>Created:</strong> ${PersistenceCore.formatTimestamp(vm.created)}</p>
                    </div>
                    <div class="settings-section">
                        <h4>Resources</h4>
                        <p><strong>CPU Cores:</strong> ${vm.cpu}</p>
                        <p><strong>Memory:</strong> ${vm.memory} GB</p>
                        <p><strong>Storage:</strong> ${vm.storage} GB</p>
                    </div>
                    <div class="settings-section">
                        <h4>Performance</h4>
                        <p><strong>CPU Usage:</strong> ${vm.cpuUsage}%</p>
                        <p><strong>Memory Usage:</strong> ${vm.memoryUsage}%</p>
                        <p><strong>Uptime:</strong> ${vm.uptime}</p>
                    </div>
                </div>
                <div class="modal-footer">
                    <button onclick="closeVMSettingsModal()" class="btn btn-secondary">Close</button>
                </div>
            </div>
        </div>
    `;
    
    // Add modal to DOM
    document.body.insertAdjacentHTML('beforeend', modalHtml);
    document.body.classList.add('modal-open');
    
    // Add close function to window
    window.closeVMSettingsModal = () => {
        const modal = document.getElementById('vmSettingsModal');
        if (modal) {
            modal.remove();
            document.body.classList.remove('modal-open');
        }
        delete window.closeVMSettingsModal;
    };
}

// =============================================================================
// VM MONITORING
// =============================================================================

/**
 * Start VM monitoring with automatic refresh
 */
function startVMMonitoring() {
    console.log('📊 Starting enhanced VM monitoring...');
    
    // Clear existing interval
    if (vmState.refreshInterval) {
        clearInterval(vmState.refreshInterval);
    }
    
    // Set up refresh interval
    vmState.refreshInterval = setInterval(async () => {
        if (!vmState.vmLoading) {
            await refreshVMs();
        }
    }, PersistenceCore.config.REFRESH_INTERVALS.VM_DATA);
    
    // Initial refresh
    refreshVMs();
}

/**
 * Stop VM monitoring
 */
function stopVMMonitoring() {
    console.log('âšī¸ Stopping VM monitoring...');
    
    if (vmState.refreshInterval) {
        clearInterval(vmState.refreshInterval);
        vmState.refreshInterval = null;
    }
}

// =============================================================================
// INITIALIZATION
// =============================================================================

/**
 * Initialize VM module
 */
function initializeVMModule() {
    console.log('đŸ–Ĩī¸ Initializing VM management module...');
    
    // Start monitoring if authenticated
    if (PersistenceAuth.state.isAuthenticated) {
        startVMMonitoring();
    }
    
    // Listen for authentication changes
    window.addEventListener('auth-state-changed', (event) => {
        if (event.detail.isAuthenticated) {
            startVMMonitoring();
        } else {
            stopVMMonitoring();
        }
    });
}

// Initialize on DOM ready
document.addEventListener('DOMContentLoaded', initializeVMModule);

// =============================================================================
// EXPORT FOR MODULE SYSTEM
// =============================================================================

window.PersistenceVM = {
    state: vmState,
    refreshVMs,
    getVMStats,
    performVMAction,
    createVM,
    deleteVM,
    openVMConsole,
    showVMSettings,
    startVMMonitoring,
    stopVMMonitoring,
    initializeVMModule
};

console.log('✅ PersistenceOS VM Management Module loaded');
openSUSE Build Service is sponsored by