/**
 * sandbox.js - AI流程管理 沙箱执行环境
 * 
 * 职责：安全执行Skill中的代码逻辑
 * 安全策略：完全隔离 + 白名单API
 */

class Sandbox {
  constructor(options = {}) {
    this.allowedGlobals = new Set([
      'console',
      'setTimeout',
      'clearTimeout',
      'setInterval',
      'clearInterval',
      'Promise',
      'Array',
      'Object',
      'String',
      'Number',
      'Boolean',
      'Date',
      'Math',
      'JSON',
      'RegExp',
      'Error',
      'Map',
      'Set',
      'WeakMap',
      'WeakSet',
      'Symbol',
      'parseInt',
      'parseFloat',
      'isNaN',
      'isFinite',
      'encodeURIComponent',
      'decodeURIComponent',
      'encodeURI',
      'decodeURI',
      'btoa',
      'atob',
      ...options.additionalGlobals || []
    ]);
    
    this.timeout = options.timeout || 5000;
    this.memoryLimit = options.memoryLimit || 10 * 1024 * 1024; // 10MB
    this.callDepth = 0;
    this.maxCallDepth = options.maxCallDepth || 100;
  }

  /**
   * 创建安全的全局对象
   */
  createSecureContext() {
    const secureContext = {};
    
    // 复制允许的全局变量
    this.allowedGlobals.forEach(name => {
      if (typeof globalThis[name] !== 'undefined') {
        secureContext[name] = globalThis[name];
      }
    });
    
    // 重写console，限制输出
    secureContext.console = this.createSecureConsole();
    
    // 添加沙箱专用工具
    secureContext.Sandbox = {
      exit: (result) => { throw new SandboxExit(result); },
      sleep: (ms) => new Promise(r => setTimeout(r, ms)),
      now: () => Date.now()
    };
    
    return secureContext;
  }

  /**
   * 创建安全的console
   */
  createSecureConsole() {
    const maxLogs = 100;
    let logCount = 0;
    
    const checkLimit = () => {
      logCount++;
      if (logCount > maxLogs) {
        throw new Error('Console output limit exceeded');
      }
    };
    
    return {
      log: (...args) => { checkLimit(); console.log('[Sandbox]', ...args); },
      warn: (...args) => { checkLimit(); console.warn('[Sandbox]', ...args); },
      error: (...args) => { checkLimit(); console.error('[Sandbox]', ...args); },
      info: (...args) => { checkLimit(); console.info('[Sandbox]', ...args); },
      debug: (...args) => { checkLimit(); console.debug('[Sandbox]', ...args); }
    };
  }

  /**
   * 执行代码
   * @param {string} code - 要执行的代码
   * @param {Object} context - 额外上下文
   * @returns {Promise<any>} 执行结果
   */
  async execute(code, context = {}) {
    throw new Error('code.execute 已在个人助理版中禁用，以符合 Chrome 扩展安全策略');
  }

  /**
   * 代码预处理
   */
  preprocessCode(code) {
    // 检查危险关键字
    const dangerous = [
      'eval\\s*\\(',
      'Function\\s*\\(',
      'constructor\\s*\\[',
      'prototype\\s*\\[',
      '__proto__',
      'importScripts',
      'XMLHttpRequest',
      'WebSocket',
      'Worker',
      'SharedArrayBuffer',
      'Atomics'
    ];
    
    for (const pattern of dangerous) {
      if (new RegExp(pattern, 'i').test(code)) {
        throw new Error(`Dangerous code detected: ${pattern}`);
      }
    }
    
    // 包装返回值
    return `
      try {
        let __sandbox_result__ = (async () => {
          ${code}
        })();
        if (__sandbox_result__ instanceof Promise) {
          return await __sandbox_result__;
        }
        return __sandbox_result__;
      } catch (e) {
        if (e instanceof SandboxExit) {
          return e.result;
        }
        throw e;
      }
    `;
  }

  /**
   * 带守护的执行
   */
  async runWithGuard(fn, args) {
    return new Promise((resolve, reject) => {
      const timeoutId = setTimeout(() => {
        reject(new Error('Sandbox execution timeout'));
      }, this.timeout);
      
      try {
        const result = fn(...args);
        clearTimeout(timeoutId);
        resolve(result);
      } catch (error) {
        clearTimeout(timeoutId);
        reject(error);
      }
    });
  }

  /**
   * 执行表达式（简化版）
   */
  evaluate(expression, context = {}) {
    throw new Error('表达式执行已在个人助理版中禁用，以符合 Chrome 扩展安全策略');
  }
}

/**
 * 沙箱退出异常
 */
class SandboxExit extends Error {
  constructor(result) {
    super('Sandbox exit');
    this.result = result;
  }
}

// ==================== 文件解析沙箱 ====================

class FileParserSandbox {
  constructor() {
    this.parsers = new Map();
    this.initParsers();
  }

  initParsers() {
    // Excel解析器
    this.parsers.set('excel', {
      extensions: ['.xlsx', '.xls', '.csv'],
      parse: this.parseExcel.bind(this)
    });
    
    // PDF解析器
    this.parsers.set('pdf', {
      extensions: ['.pdf'],
      parse: this.parsePDF.bind(this)
    });
    
    // Word解析器
    this.parsers.set('word', {
      extensions: ['.docx', '.doc'],
      parse: this.parseWord.bind(this)
    });
    
    // 图片解析器
    this.parsers.set('image', {
      extensions: ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'],
      parse: this.parseImage.bind(this)
    });
    
    // 文本解析器
    this.parsers.set('text', {
      extensions: ['.txt', '.md', '.json', '.js', '.html', '.css', '.xml'],
      parse: this.parseText.bind(this)
    });
  }

  /**
   * 检测文件类型
   */
  detectType(filename) {
    const ext = filename.toLowerCase().slice(filename.lastIndexOf('.'));
    for (const [type, config] of this.parsers) {
      if (config.extensions.includes(ext)) {
        return type;
      }
    }
    return 'text';
  }

  /**
   * 解析文件
   */
  async parse(file) {
    const type = this.detectType(file.name);
    const parser = this.parsers.get(type);
    
    if (!parser) {
      throw new Error(`No parser available for ${file.name}`);
    }
    
    return await parser.parse(file);
  }

  /**
   * 解析Excel
   */
  async parseExcel(file) {
    // 需要加载xlsx库
    if (!window.XLSX) {
      await this.loadScript('libs/xlsx.min.js');
    }
    
    const data = await file.arrayBuffer();
    const workbook = window.XLSX.read(data, { type: 'array' });
    
    const result = {
      sheets: {},
      sheetNames: workbook.SheetNames
    };
    
    workbook.SheetNames.forEach(sheetName => {
      const worksheet = workbook.Sheets[sheetName];
      result.sheets[sheetName] = window.XLSX.utils.sheet_to_json(worksheet, { header: 1 });
    });
    
    return result;
  }

  /**
   * 解析PDF（简化版，需要PDF.js）
   */
  async parsePDF(file) {
    // 返回文件信息，实际解析需要PDF.js
    return {
      type: 'pdf',
      name: file.name,
      size: file.size,
      text: '[PDF content extraction requires PDF.js library]'
    };
  }

  /**
   * 解析Word（简化版，需要mammoth.js）
   */
  async parseWord(file) {
    // 返回文件信息，实际解析需要mammoth.js
    return {
      type: 'word',
      name: file.name,
      size: file.size,
      text: '[Word content extraction requires mammoth.js library]'
    };
  }

  /**
   * 解析图片
   */
  async parseImage(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        resolve({
          type: 'image',
          name: file.name,
          size: file.size,
          dataUrl: e.target.result,
          mimeType: file.type
        });
      };
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  }

  /**
   * 解析文本
   */
  async parseText(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        resolve({
          type: 'text',
          name: file.name,
          size: file.size,
          content: e.target.result
        });
      };
      reader.onerror = reject;
      reader.readAsText(file);
    });
  }

  /**
   * 加载随扩展打包的本地脚本
   */
  async loadScript(path) {
    if (/^https?:\/\//i.test(path)) {
      throw new Error('个人助理版禁止加载远程脚本');
    }
    return new Promise((resolve, reject) => {
      const script = document.createElement('script');
      script.src = typeof chrome !== 'undefined' && chrome.runtime
        ? chrome.runtime.getURL(path.replace(/^\/+/, ''))
        : path;
      script.onload = resolve;
      script.onerror = reject;
      document.head.appendChild(script);
    });
  }
}

// ==================== 导出 ====================

if (typeof module !== 'undefined' && module.exports) {
  module.exports = { Sandbox, FileParserSandbox, SandboxExit };
} else {
  window.Sandbox = Sandbox;
  window.FileParserSandbox = FileParserSandbox;
  window.SandboxExit = SandboxExit;
}
