#!/usr/bin/env node

/**
 * Shell Script Compiler using shc
 * Compiles shell scripts to binary executables for protection
 */

const { execSync, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');

const SCRIPTS_DIR = path.join(__dirname, 'shell');
const DIST_SHELL_DIR = path.join(__dirname, '../dist/scripts/shell');

// Ensure dist directory structure exists
function ensureDistStructure() {
  const dirs = [
    path.join(__dirname, '../dist'),
    path.join(__dirname, '../dist/scripts'),
    DIST_SHELL_DIR
  ];
  
  dirs.forEach(dir => {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
  });
}

// Check if shc is installed
function checkShcInstalled() {
  try {
    execSync('which shc', { stdio: 'pipe' });
    return true;
  } catch (error) {
    return false;
  }
}

// Install shc if not present
function installShc() {
  console.log('📥 Installing shc (Shell Script Compiler)...');
  
  const platform = os.platform();
  
  try {
    if (platform === 'darwin') {
      console.log('   Using Homebrew to install shc...');
      execSync('brew install shc', { stdio: 'inherit' });
    } else if (platform === 'linux') {
      console.log('   Installing shc on Linux...');
      // Try different package managers
      try {
        execSync('sudo apt-get update && sudo apt-get install -y shc', { stdio: 'inherit' });
      } catch (e) {
        try {
          execSync('sudo yum install -y shc', { stdio: 'inherit' });
        } catch (e2) {
          console.error('❌ Could not install shc. Please install manually.');
          return false;
        }
      }
    } else {
      console.error('❌ Unsupported platform for automatic shc installation.');
      return false;
    }
    console.log('✅ shc installed successfully!');
    return true;
  } catch (error) {
    console.error('❌ Failed to install shc:', error.message);
    return false;
  }
}

// Compile a single shell script
function compileShellScript(scriptPath, outputDir) {
  const scriptName = path.basename(scriptPath, '.sh');
  const outputBinary = path.join(outputDir, scriptName);
  
  console.log(`🔒 Compiling: ${scriptName}.sh -> ${scriptName} (binary)`);
  
  try {
    // Copy script to output directory first
    const tempScript = path.join(outputDir, path.basename(scriptPath));
    fs.copyFileSync(scriptPath, tempScript);
    
    // Compile with shc
    // -f: input file
    // -o: output binary file
    // -r: make binary relocatable (not require original .sh file)
    // -v: verbose
    const cmd = `shc -r -f "${tempScript}" -o "${outputBinary}"`;
    execSync(cmd, { stdio: 'pipe' });
    
    // Make binary executable
    fs.chmodSync(outputBinary, 0o755);
    
    // Clean up temporary files created by shc
    const tempFiles = [
      tempScript + '.x.c',  // C source file
      tempScript           // Original script copy
    ];
    
    tempFiles.forEach(file => {
      if (fs.existsSync(file)) {
        fs.unlinkSync(file);
      }
    });
    
    console.log(`   ✓ Binary created: ${scriptName}`);
    return true;
  } catch (error) {
    console.error(`   ❌ Failed to compile ${scriptName}:`, error.message);
    // Copy the original script as fallback
    fs.copyFileSync(scriptPath, path.join(outputDir, path.basename(scriptPath)));
    console.log(`   ⚠️  Fallback: Copied original script`);
    return false;
  }
}

// Compile all shell scripts
function compileAllScripts() {
  console.log('\n🛡️  Shell Script Protection Starting...\n');
  
  // Ensure dist structure exists
  ensureDistStructure();
  
  // Check/install shc
  if (!checkShcInstalled()) {
    console.log('⚠️  shc not found. Attempting to install...');
    if (!installShc()) {
      console.error('❌ Cannot proceed without shc. Exiting...');
      process.exit(1);
    }
  } else {
    console.log('✅ shc is installed');
  }
  
  // Ensure output directory exists
  if (!fs.existsSync(DIST_SHELL_DIR)) {
    fs.mkdirSync(DIST_SHELL_DIR, { recursive: true });
  }
  
  // Get all shell scripts
  if (!fs.existsSync(SCRIPTS_DIR)) {
    console.error(`❌ Scripts directory not found: ${SCRIPTS_DIR}`);
    process.exit(1);
  }
  
  const shellScripts = fs.readdirSync(SCRIPTS_DIR)
    .filter(file => file.endsWith('.sh'))
    .map(file => path.join(SCRIPTS_DIR, file));
  
  if (shellScripts.length === 0) {
    console.log('⚠️  No shell scripts found to compile');
    return;
  }
  
  console.log(`\n📋 Found ${shellScripts.length} shell scripts to compile\n`);
  
  let successCount = 0;
  let failCount = 0;
  
  // Compile each script
  shellScripts.forEach(scriptPath => {
    if (compileShellScript(scriptPath, DIST_SHELL_DIR)) {
      successCount++;
    } else {
      failCount++;
    }
  });
  
  // Summary
  console.log('\n' + '='.repeat(60));
  console.log('📊 Compilation Summary');
  console.log('='.repeat(60));
  console.log(`✅ Successfully compiled: ${successCount}`);
  if (failCount > 0) {
    console.log(`⚠️  Failed compilations: ${failCount}`);
  }
  console.log('='.repeat(60));
  
  // Remove .sh files from distribution (keep only binaries)
  console.log('\n🗑️  Removing .sh files from distribution (keeping only binaries)...');
  const shFiles = fs.readdirSync(DIST_SHELL_DIR).filter(f => f.endsWith('.sh'));
  shFiles.forEach(shFile => {
    const filePath = path.join(DIST_SHELL_DIR, shFile);
    fs.unlinkSync(filePath);
    console.log(`   ✓ Removed: ${shFile}`);
  });
  
  console.log('\n✅ Shell script protection complete!');
  console.log(`📁 Protected scripts in: ${DIST_SHELL_DIR}`);
  console.log(`🛡️  Only binary executables remain (${successCount} files)\n`);
}

// Run if called directly
if (require.main === module) {
  try {
    compileAllScripts();
  } catch (error) {
    console.error('❌ Error during compilation:', error);
    process.exit(1);
  }
}

module.exports = { compileAllScripts, compileShellScript };
