#!/usr/bin/env node

/**
 * Shell Script Obfuscator
 * Obfuscates shell scripts using base64 encoding and encryption
 * Cross-platform compatible
 */

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Generate a key from package info (consistent across installations)
function generateKey() {
  const pkg = require('../package.json');
  return crypto.createHash('sha256').update(pkg.name + pkg.version).digest();
}

// Encrypt script content
function encryptScript(content) {
  const key = generateKey();
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
  
  let encrypted = cipher.update(content, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  return {
    iv: iv.toString('hex'),
    content: encrypted
  };
}

// Create wrapper script that decrypts and executes
function createWrapper(scriptName, encrypted) {
  return `#!/bin/bash
# Protected Shell Script - Devicely
# This script is encrypted for code protection

SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
NODE_BIN="node"

# Check if node is available
if ! command -v node &> /dev/null; then
    echo "Error: Node.js is required to run Devicely"
    exit 1
fi

# Decrypt and execute
$NODE_BIN -e "
const crypto = require('crypto');
const pkg = require('$SCRIPT_DIR/../../package.json');

function generateKey() {
  return crypto.createHash('sha256').update(pkg.name + pkg.version).digest();
}

function decrypt(iv, content) {
  const key = generateKey();
  const decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));
  let decrypted = decipher.update(content, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}

const encrypted = {
  iv: '${encrypted.iv}',
  content: '${encrypted.content}'
};

const script = decrypt(encrypted.iv, encrypted.content);
const { spawn } = require('child_process');

// Get arguments passed to this wrapper
// When called as: node -e "..." -- arg1 arg2
// process.argv is: ['/path/to/node', 'arg1', 'arg2', ...]
// So we need slice(1) not slice(2)
const args = process.argv.slice(1);

// Create a temporary file for the decrypted script
const tmpScript = require('path').join(require('os').tmpdir(), 'devicely_' + Date.now() + '.sh');
require('fs').writeFileSync(tmpScript, script, { mode: 0o755 });

// Execute the decrypted script with arguments using spawn
const child = spawn(tmpScript, args, {
  stdio: 'inherit',
  env: process.env
});

child.on('exit', (code) => {
  // Clean up temp file
  try { require('fs').unlinkSync(tmpScript); } catch(e) {}
  process.exit(code || 0);
});

child.on('error', (error) => {
  // Clean up temp file on error
  try { require('fs').unlinkSync(tmpScript); } catch(e) {}
  console.error('Error executing script:', error);
  process.exit(1);
});
"
`;
}

// Obfuscate all shell scripts
function obfuscateShellScripts(shellDir, outputDir) {
  console.log('🔐 Obfuscating shell scripts...');
  
  if (!fs.existsSync(shellDir)) {
    console.error('❌ Shell scripts directory not found');
    return;
  }

  if (!fs.existsSync(outputDir)) {
    fs.mkdirSync(outputDir, { recursive: true });
  }

  const shellScripts = fs.readdirSync(shellDir).filter(f => f.endsWith('.sh'));
  
  if (shellScripts.length === 0) {
    console.log('⚠️  No shell scripts found');
    return;
  }

  let processed = 0;
  shellScripts.forEach(script => {
    try {
      const scriptPath = path.join(shellDir, script);
      const content = fs.readFileSync(scriptPath, 'utf8');
      
      // Encrypt the script
      const encrypted = encryptScript(content);
      
      // Create wrapper script
      const wrapper = createWrapper(script, encrypted);
      
      // Write wrapper to output
      const outputPath = path.join(outputDir, script);
      fs.writeFileSync(outputPath, wrapper);
      fs.chmodSync(outputPath, 0o755);
      
      console.log(`   ✓ ${script} → encrypted wrapper`);
      processed++;
    } catch (error) {
      console.error(`   ❌ Failed to obfuscate ${script}:`, error.message);
    }
  });

  console.log(`✅ Obfuscated ${processed} shell scripts`);
}

module.exports = { obfuscateShellScripts };

// Run if called directly
if (require.main === module) {
  const shellSrc = path.join(__dirname, 'shell');
  const distShell = path.join(__dirname, '../dist/scripts/shell');
  obfuscateShellScripts(shellSrc, distShell);
}
