const BaseAction = require('../core/base-action');

/**
 * 数据提取动作 - 从页面提取数据并保存到上下文
 * 
 * Example:
 * - action: extract
 *   name: Extract quota info
 *   selector: p.caption1
 *   extractType: text
 *   regex: (\\d+)\\s*\\/\\s*(\\d+)
 *   saveTo:
 *     used: $1
 *     total: $2
 *   contextKey: quotaInfo
 */
class ExtractAction extends BaseAction {
  async execute() {
    const {
      selector,
      extractType = 'text',
      regex,
      saveTo,
      contextKey,
      filter,
      multiple = false,
      required = true
    } = this.config;
    
    if (!selector) {
      throw new Error('Extract action 需要 selector 参数');
    }
    
    this.log('debug', `提取数据: ${selector}`);
    
    try {
      // 在页面中查找并提取数据
      const extractedData = await this.page.evaluate((config) => {
        const { selector, extractType, filter, multiple } = config;
        
        // 查找元素
        let elements = Array.from(document.querySelectorAll(selector));
        
        // 过滤元素
        if (filter) {
          if (filter.contains) {
            elements = elements.filter(el => 
              el.textContent.includes(filter.contains)
            );
          }
          if (filter.notContains) {
            elements = elements.filter(el => 
              !el.textContent.includes(filter.notContains)
            );
          }
        }
        
        if (elements.length === 0) {
          return null;
        }
        
        // 提取数据
        const extractFrom = (element) => {
          switch (extractType) {
            case 'text':
              return element.textContent.trim();
            case 'html':
              return element.innerHTML;
            case 'attribute':
              return element.getAttribute(config.attribute);
            case 'value':
              return element.value;
            default:
              return element.textContent.trim();
          }
        };
        
        if (multiple) {
          return elements.map(extractFrom);
        } else {
          return extractFrom(elements[0]);
        }
      }, { selector, extractType, filter, multiple, attribute: this.config.attribute });
      
      if (extractedData === null) {
        if (required) {
          throw new Error(`未找到匹配的元素: ${selector}`);
        } else {
          this.log('warn', `未找到元素: ${selector}，跳过提取`);
          return { success: true, data: null };
        }
      }
      
      this.log('debug', `提取到原始数据: ${JSON.stringify(extractedData)}`);
      
      // 应用正则表达式
      let processedData = extractedData;
      if (regex && typeof extractedData === 'string') {
        const regexObj = new RegExp(regex);
        const match = extractedData.match(regexObj);
        
        if (match) {
          // 如果有 saveTo 配置，使用捕获组
          if (saveTo && typeof saveTo === 'object') {
            processedData = {};
            for (const [key, value] of Object.entries(saveTo)) {
              // $1, $2 等替换为捕获组
              if (typeof value === 'string' && value.startsWith('$')) {
                const groupIndex = parseInt(value.substring(1));
                processedData[key] = match[groupIndex] || null;
              } else {
                processedData[key] = value;
              }
            }
          } else {
            // 返回第一个捕获组或整个匹配
            processedData = match[1] || match[0];
          }
        } else if (required) {
          throw new Error(`正则表达式不匹配: ${regex}`);
        } else {
          this.log('warn', `正则表达式不匹配: ${regex}`);
          processedData = null;
        }
      }
      
      // 保存到上下文
      if (contextKey && processedData !== null) {
        if (!this.context.data) {
          this.context.data = {};
        }
        this.context.data[contextKey] = processedData;
        this.log('info', `✓ 数据已保存到 context.${contextKey}`);
      }
      
      this.log('debug', `处理后的数据: ${JSON.stringify(processedData)}`);
      
      return { success: true, data: processedData };
      
    } catch (error) {
      this.log('error', `数据提取失败: ${error.message}`);
      throw error;
    }
  }
}

module.exports = ExtractAction;
