/**
 * 安全沙箱工具
 * 用于替代 new Function() 执行不可信代码
 * 提供安全的代码执行环境，限制对系统资源的访问
 */

const { VM, VMScript } = require('vm2')

/**
 * 创建安全的沙箱上下文
 * @param {Object} customContext - 自定义上下文变量
 * @param {Object} options - 配置选项
 * @returns {Object} 沙箱上下文
 */
function createSandboxContext(customContext = {}, options = {}) {
  const {
    timeout = 5000,        // 超时时间（毫秒）
    allowSync = false,     // 是否允许同步执行
    mockConsole = true      // 是否模拟 console
  } = options

  // 创建安全的 console 对象
  const safeConsole = mockConsole ? {
    log: (...args) => { /* 静默执行，阻止日志泄露 */ },
    error: (...args) => { /* 静默执行 */ },
    warn: (...args) => { /* 静默执行 */ },
    info: (...args) => { /* 静默执行 */ },
    debug: (...args) => { /* 静默执行 */ }
  } : console

  return {
    // 用户提供的上下文
    ...customContext,
    // 安全的 console
    console: safeConsole,
    // 安全的 Math 对象
    Math,
    // 安全的 JSON 对象
    JSON: {
      parse: JSON.parse,
      stringify: JSON.stringify
    },
    // 安全的 Array 对象（限制方法）
    Array: {
      isArray: Array.isArray,
      from: Array.from,
      of: Array.of
    },
    // 安全的 String 对象
    String: {
      fromCharCode: String.fromCharCode,
      fromCodePoint: String.fromCodePoint,
      raw: String.raw
    },
    // 安全的 Number 对象
    Number: {
      isNaN: Number.isNaN,
      isFinite: Number.isFinite,
      parseInt: Number.parseInt,
      parseFloat: Number.parseFloat
    },
    // 安全的 Boolean 对象
    Boolean,
    // 安全的 Object 对象
    Object: {
      keys: Object.keys,
      values: Object.values,
      entries: Object.entries,
      assign: Object.assign,
      create: Object.create,
      freeze: Object.freeze
    },
    // 安全的 Date 对象
    Date: {
      now: Date.now
    },
    // 安全的 RegExp 对象
    RegExp,
    // 安全的 Error 对象
    Error,
    // 安全的 Promise 对象
    Promise,
    // 安全的 Set 对象
    Set,
    // 安全的 Map 对象
    Map,
    // 安全的 WeakMap 对象
    WeakMap,
    // 安全的 WeakSet 对象
    WeakSet,
    // 安全的 Symbol
    Symbol,
    // 安全的 Proxy
    Proxy,
    // 安全的 Reflect
    Reflect
  }
}

/**
 * 在沙箱中执行异步代码
 * @param {string} code - 要执行的代码
 * @param {Object} context - 上下文变量
 * @param {Object} options - 配置选项
 * @returns {Promise<any>} 执行结果
 */
async function runInSandbox(code, context = {}, options = {}) {
  const { timeout = 5000 } = options

  try {
    const vm = new VM({
      timeout,
      sandbox: createSandboxContext(context, options),
      eval: false,
      wasm: false
    })

    // 包装代码为异步函数
    const wrappedCode = `(async () => { ${code} })()`
    return await vm.run(wrappedCode)
  } catch (error) {
    throw new Error(`Sandbox execution error: ${error.message}`)
  }
}

/**
 * 在沙箱中执行表达式（同步）
 * @param {string} expression - 要执行的表达式
 * @param {Object} context - 上下文变量
 * @param {Object} options - 配置选项
 * @returns {any} 执行结果
 */
function evaluateInSandbox(expression, context = {}, options = {}) {
  const { timeout = 5000 } = options

  try {
    const vm = new VM({
      timeout,
      sandbox: createSandboxContext(context, options),
      eval: false,
      wasm: false
    })

    return vm.run(expression)
  } catch (error) {
    throw new Error(`Sandbox evaluation error: ${error.message}`)
  }
}

/**
 * 安全执行脚本（用于工作流中的用户脚本）
 * @param {string} script - 脚本代码
 * @param {Object} context - 上下文变量
 * @param {Object} options - 配置选项
 * @returns {Promise<any>} 执行结果
 */
async function runScriptSafely(script, context = {}, options = {}) {
  const { timeout = 10000 } = options

  try {
    const vm = new VM({
      timeout,
      sandbox: createSandboxContext(context, options),
      eval: false,
      wasm: false
    })

    // 将脚本包装在异步 IIFE 中
    const wrappedCode = `
      (async () => {
        const { input, input_data, variables, previousResult, console } = context;
        ${script}
      })()
    `

    return await vm.run(wrappedCode)
  } catch (error) {
    throw new Error(`Script execution error: ${error.message}`)
  }
}

/**
 * 安全执行工作流定义
 * @param {string} workflowCode - 工作流代码
 * @param {Object} engine - 工作流引擎
 * @param {Object} options - 配置选项
 * @returns {any} 执行结果
 */
function runWorkflowSafely(workflowCode, engine, options = {}) {
  const { timeout = 5000 } = options

  try {
    const vm = new VM({
      timeout,
      sandbox: {
        engine,
        console: {
          log: () => {},
          error: () => {},
          warn: () => {},
          info: () => {}
        },
        Math,
        JSON,
        Promise,
        Array,
        Object,
        Date,
        RegExp,
        Error,
        Symbol,
        Map,
        Set
      },
      eval: false,
      wasm: false
    })

    return vm.run(`(function(engine) { return (${workflowCode}) })(engine)`)
  } catch (error) {
    throw new Error(`Workflow execution error: ${error.message}`)
  }
}

/**
 * 安全执行工作流加载脚本
 * @param {string} content - 文件内容
 * @param {Object} options - 配置选项
 * @returns {Object} module.exports
 */
function runWorkflowFileSafely(content, options = {}) {
  const { timeout = 10000 } = options

  try {
    const vm = new VM({
      timeout,
      sandbox: {
        module: { exports: {} },
        exports: {},
        require: () => { throw new Error('require is not allowed in sandbox') },
        process: { 
          env: {},
          cwd: () => '/'
        },
        console: {
          log: () => {},
          error: () => {},
          warn: () => {},
          info: () => {}
        },
        __dirname: '/',
        __filename: '/workflow.js',
        Math,
        JSON,
        Promise,
        Array,
        Object,
        Date,
        RegExp,
        Error,
        Symbol,
        Map,
        Set
      },
      eval: false,
      wasm: false
    })

    const wrappedCode = `
      (function(module, exports, require, process, console, __dirname, __filename) {
        ${content}
      })
    `

    const fn = vm.run(wrappedCode)
    const moduleObj = { exports: {} }
    fn(moduleObj, moduleObj.exports, () => {}, { env: {}, cwd: () => '/' }, { log: () => {}, error: () => {}, warn: () => {}, info: () => {} }, '/', '/workflow.js')
    
    return moduleObj.exports.default || moduleObj.exports
  } catch (error) {
    throw new Error(`Workflow file execution error: ${error.message}`)
  }
}

module.exports = {
  createSandboxContext,
  runInSandbox,
  evaluateInSandbox,
  runScriptSafely,
  runWorkflowSafely,
  runWorkflowFileSafely
}
