Source: main/ipc/ctraceHandlers.js

const { ipcMain } = require('electron');
const { spawn } = require('child_process');
const path = require('path');
const fs = require('fs').promises;
const os = require('os');

/**
 * Check if WSL is available and has distributions installed
 * @returns {Promise<Object>} WSL status object with properties: available (boolean), hasDistros (boolean), error (string)
 */
async function checkWSLAvailability() {
  return new Promise((resolve) => {
    // First check if WSL command exists
    const statusChild = spawn('wsl', ['--status'], { stdio: 'pipe' });
    
    let statusOutput = '';
    let statusError = '';
    
    statusChild.stdout.on('data', (data) => {
      statusOutput += data.toString();
    });
    
    statusChild.stderr.on('data', (data) => {
      statusError += data.toString();
    });
    
    statusChild.on('error', () => {
      resolve({ available: false, hasDistros: false, error: 'WSL is not installed' });
    });
    
    statusChild.on('close', (statusCode) => {
      if (statusCode !== 0) {
        resolve({ available: false, hasDistros: false, error: 'WSL is not available' });
        return;
      }
      
      // WSL exists, now check for installed distributions
      const listChild = spawn('wsl', ['--list', '--quiet'], { stdio: 'pipe' });
      
      let listOutput = '';
      
      listChild.stdout.on('data', (data) => {
        listOutput += data.toString();
      });
      
      listChild.on('error', () => {
        resolve({ available: true, hasDistros: false, error: 'Cannot check WSL distributions' });
      });
      
      listChild.on('close', (listCode) => {
        const distributions = listOutput.trim().split('\n').filter(line => line.trim().length > 0);
        const hasDistros = distributions.length > 0 && !listOutput.includes('no installed distributions');
        
        if (!hasDistros) {
          const errorMsg = statusError.includes('no installed distributions') || listOutput.includes('no installed distributions')
            ? 'WSL is installed but no Linux distributions are available'
            : 'No WSL distributions found';
          resolve({ available: true, hasDistros: false, error: errorMsg });
        } else {
          resolve({ available: true, hasDistros: true });
        }
      });
      
      // Timeout for list command
      setTimeout(() => {
        listChild.kill();
        resolve({ available: true, hasDistros: false, error: 'Timeout checking WSL distributions' });
      }, 5000);
    });
    
    // Timeout for status command
    setTimeout(() => {
      statusChild.kill();
      resolve({ available: false, hasDistros: false, error: 'Timeout checking WSL status' });
    }, 5000);
  });
}

/**
 * Setup IPC handlers for running the ctrace binary
 */
function setupCtraceHandlers() {
  ipcMain.handle('run-ctrace', async (event, args = []) => {
    // Always use the Linux binary 'ctrace' (no .exe extension)
    // On Windows, this will be executed through WSL
    const binaryName = 'ctrace';
    
    // Resolve binary in dev and production (packaged) locations
    let binPath;
    
    if (process.resourcesPath) {
      // In packaged app, binary is in extraResources
      binPath = path.join(process.resourcesPath, 'bin', binaryName);
    } else {
      // In development, binary is in the project bin directory
      // __dirname is .../src/main/ipc, so project root bin is ../../../bin/ctrace
      binPath = path.join(__dirname, '../../../bin', binaryName);
    }

    async function resolveBinary() {
      try {
        await fs.access(binPath);
        return binPath;
      } catch (error) {
        console.error(`Binary not found at ${binPath}:`, error.message);
        return null;
      }
    }

    try {
      const resolvedBinPath = await resolveBinary();
      if (!resolvedBinPath) {
        const platform = os.platform();
        const platformInfo = platform === 'win32' ? ' (Linux binary executed via WSL)' : '';
        const checkedPath = process.resourcesPath ? 
          path.join(process.resourcesPath, 'bin', binaryName) : 
          path.join(__dirname, '../../../bin', binaryName);
        return { 
          success: false, 
          error: `ctrace binary not found at: ${checkedPath}${platformInfo}` 
        };
      }

      // On Windows, check if WSL is available before proceeding
      if (os.platform() === 'win32') {
        const wslStatus = await checkWSLAvailability();
        if (!wslStatus.available || !wslStatus.hasDistros) {
          let errorMessage = 'CTrace requires WSL (Windows Subsystem for Linux) to run on Windows.\n\n';
          
          if (!wslStatus.available) {
            errorMessage += 'WSL is not installed. Please install WSL by running:\n';
            errorMessage += '• Open PowerShell as Administrator\n';
            errorMessage += '• Run: wsl --install\n';
            errorMessage += '• Restart your computer when prompted\n\n';
          } else if (!wslStatus.hasDistros) {
            errorMessage += 'WSL is installed but no Linux distributions are available.\n\n';
            errorMessage += 'To fix this:\n';
            errorMessage += '• Run: wsl --list --online (to see available distributions)\n';
            errorMessage += '• Run: wsl --install Ubuntu (or another distribution)\n';
            errorMessage += '• Follow the setup instructions\n\n';
          }
          
          errorMessage += 'After setup, restart the application to use CTrace.';
          
          if (wslStatus.error) {
            errorMessage += `\n\nDetailed error: ${wslStatus.error}`;
          }
          
          return { 
            success: false, 
            error: errorMessage
          };
        }
      }

      return await new Promise((resolve) => {
        console.log('args', args);
        
        let command, commandArgs;
        
        // Check if we're on Windows (we always have a Linux binary now)
        if (os.platform() === 'win32') {
          // On Windows, use WSL to execute the Linux binary
          console.log('Windows detected, using WSL to execute ctrace');
          console.log('Binary path:', resolvedBinPath);
          
          // Convert Windows path to WSL path
          const wslPath = resolvedBinPath.replace(/\\/g, '/').replace(/^([A-Z]):/, (match, drive) => `/mnt/${drive.toLowerCase()}`);
          command = 'wsl';
          
          // Convert arguments with Windows paths to WSL paths
          const convertedArgs = (Array.isArray(args) ? args : []).map(arg => {
            // Convert paths in arguments like --input=C:\path\to\file
            if (typeof arg === 'string' && arg.includes(':\\')) {
              return arg.replace(/([A-Z]):\\/g, (match, drive) => `/mnt/${drive.toLowerCase()}/`).replace(/\\/g, '/');
            }
            return arg;
          });
          
          commandArgs = [wslPath, ...convertedArgs];
          console.log('WSL command:', command, commandArgs);
        } else {
          // On Linux/Mac, use the binary directly
          command = resolvedBinPath;
          commandArgs = Array.isArray(args) ? args : [];
          console.log('Direct execution:', command, commandArgs);
        }
        
        const child = spawn(command, commandArgs, {
          stdio: ['ignore', 'pipe', 'pipe']
        });

        let stdout = '';
        let stderr = '';

        child.stdout.on('data', (data) => {
          stdout += data.toString();
        });

        child.stderr.on('data', (data) => {
          stderr += data.toString();
        });

        child.on('error', (err) => {
          let errorMessage = err.message;
          
          // Provide more helpful error messages for WSL-related issues
          if (os.platform() === 'win32' && command === 'wsl') {
            if (err.code === 'ENOENT') {
              errorMessage = 'WSL (Windows Subsystem for Linux) is not installed or not available in PATH. Please install WSL to use CTrace.';
            } else if (err.code === 'EACCES') {
              errorMessage = 'Permission denied when trying to execute WSL. Please check WSL installation and permissions.';
            } else {
              errorMessage = `WSL execution failed: ${err.message}`;
            }
          }
          
          resolve({ success: false, error: errorMessage });
        });

        child.on('close', (code) => {
          if (code === 0) {
            resolve({ success: true, output: stdout, exitCode: code });
          } else {
            resolve({ success: false, error: `ctrace exited with code ${code}`, stderr, output: stdout, exitCode: code });
          }
        });
      });
    } catch (error) {
      return { success: false, error: error.message };
    }
  });
}

module.exports = { setupCtraceHandlers };