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

/**
 * 点击动作
 */
class ClickAction extends BaseAction {
  async execute() {
    const selector = this.config.selector || this.config.find;
    
    if (!selector) {
      throw new Error('缺少选择器配置');
    }
    
    this.log('info', '执行点击');
    
    // 查找元素
    const smartSelector = SmartSelector.fromConfig(selector, this.page);
    const element = await smartSelector.find(this.config.timeout || 10000);
    
    if (!element) {
      throw new Error(`无法找到元素: ${JSON.stringify(selector)}`);
    }
    
    // 等待元素变为可点击状态（参考旧框架）
    const waitForEnabled = this.config.waitForEnabled !== false; // 默认等待
    if (waitForEnabled) {
      // 传入 selector 配置，在循环中重新查找元素
      await this.waitForClickable(element, this.config.timeout || 30000, selector);
    }
    
    // 记录找到的元素信息（总是显示，便于调试）
    try {
      const info = await element.evaluate((el) => {
        const tag = el.tagName;
        const id = el.id ? `#${el.id}` : '';
        const cls = el.className ? `.${el.className.split(' ')[0]}` : '';
        const text = (el.textContent || '').trim().substring(0, 30);
        const disabled = el.disabled ? ' [DISABLED]' : '';
        return `${tag}${id}${cls} "${text}"${disabled}`;
      });
      this.log('info', `→ 找到元素: ${info}`);
    } catch (e) {
      this.log('warn', `无法获取元素信息: ${e.message}`);
    }
    
    // 滚动到可视区域（带容错）
    try {
      await element.evaluate((el) => {
        if (el && typeof el.scrollIntoView === 'function') {
          el.scrollIntoView({ behavior: 'smooth', block: 'center' });
        }
      });
      
      await new Promise(resolve => setTimeout(resolve, 300));
    } catch (error) {
      this.log('warn', `滚动失败，继续尝试点击: ${error.message}`);
    }
    
    // 点击（支持人类行为模拟）
    const humanLike = this.config.humanLike !== false; // 默认使用人类行为
    if (humanLike) {
      // 重新查找元素并点击（参考旧框架，避免元素失效）
      await this.humanClickWithSelector(selector);
    } else {
      await element.click();
    }
    
    this.log('info', '✓ 点击完成');
    
    // 验证点击后的变化（新元素出现 / 旧元素消失）
    if (this.config.verifyAfter) {
      await this.verifyAfterClick(this.config.verifyAfter);
    }
    
    // 等待页面变化（如果配置了）
    if (this.config.waitForPageChange) {
      await this.waitForPageChange(this.config.checkSelector);
    }
    
    // 可选的等待时间
    if (this.config.waitAfter) {
      await new Promise(resolve => setTimeout(resolve, this.config.waitAfter));
    }
    
    return { success: true };
  }
  
  /**
   * 等待元素变为可点击状态（参考旧框架）
   * @param {ElementHandle} element - 元素句柄（可选，如果不传则在循环中重新查找）
   * @param {number} timeout - 超时时间
   * @param {Object} selectorConfig - 选择器配置（用于重新查找）
   */
  async waitForClickable(element, timeout, selectorConfig = null) {
    this.log('info', '→ 等待元素可点击...');
    
    const startTime = Date.now();
    let lastLogTime = 0;
    
    while (Date.now() - startTime < timeout) {
      try {
        // 如果提供了 selectorConfig，每次重新查找元素（参考旧框架）
        let currentElement = element;
        if (selectorConfig) {
          const smartSelector = SmartSelector.fromConfig(selectorConfig, this.page);
          currentElement = await smartSelector.find(1000);
          if (!currentElement) {
            // 元素不存在，继续等待
            await new Promise(resolve => setTimeout(resolve, 500));
            continue;
          }
        }
        
        const isClickable = await currentElement.evaluate((el) => {
          // 更严格的检查：
          // 1. 必须可见
          if (el.offsetParent === null) return false;
          // 2. 如果是 button/input，检查 disabled 属性
          if (el.tagName === 'BUTTON' || el.tagName === 'INPUT') {
            if (el.disabled) return false;
          }
          // 3. 检查是否被遮挡（可选）
          const rect = el.getBoundingClientRect();
          if (rect.width === 0 || rect.height === 0) return false;
          
          return true;
        });
        
        if (isClickable) {
          const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
          this.log('info', `✓ 元素已可点击 (耗时: ${elapsed}秒)`);
          return true;
        }
      } catch (error) {
        // 元素可能被重新渲染，继续等待
        this.log('debug', `元素检查失败: ${error.message}`);
      }
      
      // 每5秒输出一次进度
      const elapsed = Date.now() - startTime;
      if (elapsed - lastLogTime >= 5000) {
        this.log('info', `→ 等待元素可点击中... 已用时 ${(elapsed/1000).toFixed(0)}秒`);
        lastLogTime = elapsed;
      }
      
      await new Promise(resolve => setTimeout(resolve, 500));
    }
    
    this.log('warn', '⚠️ 等待元素可点击超时，将尝试点击');
    return false;
  }
  
  /**
   * 人类行为模拟点击 - 使用选择器（参考旧框架，每次重新查找元素）
   */
  async humanClickWithSelector(selectorConfig) {
    this.log('info', '→ 使用人类行为模拟点击...');
    
    try {
      // 重新查找元素（避免元素失效）
      const smartSelector = SmartSelector.fromConfig(selectorConfig, this.page);
      const element = await smartSelector.find(5000);
      
      if (!element) {
        throw new Error(`重新查找元素失败: ${JSON.stringify(selectorConfig)}`);
      }
      
      this.log('debug', '✓ 已重新定位元素');
      
      // 获取元素的边界框
      const box = await element.boundingBox();
      if (!box) {
        this.log('warn', '⚠️ 无法获取元素边界框，使用直接点击');
        await element.click();
        return;
      }
      
      this.log('debug', `元素位置: x=${box.x.toFixed(0)}, y=${box.y.toFixed(0)}, w=${box.width.toFixed(0)}, h=${box.height.toFixed(0)}`);
      
      // 计算点击位置（直接点击中心，避免随机偏移导致点击失败）
      const targetX = box.x + box.width / 2;
      const targetY = box.y + box.height / 2;
      
      // 第一段移动：先移动到附近（模拟人眼定位）
      const nearX = targetX + this.randomInt(-50, 50);
      const nearY = targetY + this.randomInt(-50, 50);
      const steps1 = this.randomInt(10, 20);
      
      this.log('debug', `移动鼠标到附近: (${nearX.toFixed(0)}, ${nearY.toFixed(0)})`);
      await this.page.mouse.move(nearX, nearY, { steps: Math.floor(steps1 / 2) });
      await this.randomDelay(50, 150);
      
      // 第二段移动：移动到目标位置
      this.log('debug', `移动鼠标到目标: (${targetX.toFixed(0)}, ${targetY.toFixed(0)})`);
      await this.page.mouse.move(targetX, targetY, { steps: Math.floor(steps1 / 2) });
      
      // 短暂停顿（模拟人类反应）
      await this.randomDelay(50, 200);
      
      // 点击（使用 down + up，而不是 click）
      this.log('debug', '执行点击 (mouse down + up)...');
      await this.page.mouse.down();
      await this.randomDelay(50, 120);
      await this.page.mouse.up();
      
      // 点击后延迟（参考旧框架）
      await this.randomDelay(1000, 2000);
      
      this.log('info', '✓ 人类行为点击完成');
      
    } catch (error) {
      this.log('error', `⚠️ 人类行为点击失败: ${error.message}`);
      throw error;
    }
  }
  
  /**
   * 随机整数
   */
  randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }
  
  /**
   * 随机延迟
   */
  async randomDelay(min, max) {
    const delay = this.randomInt(min, max);
    await new Promise(resolve => setTimeout(resolve, delay));
  }
  
  /**
   * 验证点击后的变化
   */
  async verifyAfterClick(config) {
    const { appears, disappears, checked, timeout = 10000 } = config;
    
    // 验证新元素出现
    if (appears) {
      this.log('debug', '验证新元素出现...');
      for (const selector of (Array.isArray(appears) ? appears : [appears])) {
        try {
          await this.page.waitForSelector(selector, { timeout, visible: true });
          this.log('debug', `✓ 新元素已出现: ${selector}`);
        } catch (error) {
          throw new Error(`点击后验证失败: 元素 "${selector}" 未出现`);
        }
      }
    }
    
    // 验证旧元素消失
    if (disappears) {
      this.log('debug', '验证旧元素消失...');
      for (const selector of (Array.isArray(disappears) ? disappears : [disappears])) {
        try {
          await this.page.waitForSelector(selector, { timeout, hidden: true });
          this.log('debug', `✓ 旧元素已消失: ${selector}`);
        } catch (error) {
          throw new Error(`点击后验证失败: 元素 "${selector}" 未消失`);
        }
      }
    }
    
    // 验证 checked 状态（用于 radio/checkbox）
    if (checked !== undefined) {
      this.log('debug', `验证 checked 状态: ${checked}...`);
      await new Promise(resolve => setTimeout(resolve, 500));
      
      // 获取 CSS 选择器
      const selectorConfig = this.config.selector;
      let cssSelector = null;
      
      if (typeof selectorConfig === 'string') {
        cssSelector = selectorConfig;
      } else if (Array.isArray(selectorConfig)) {
        // 取第一个 css 选择器
        for (const sel of selectorConfig) {
          if (typeof sel === 'string') {
            cssSelector = sel;
            break;
          } else if (sel.css) {
            cssSelector = sel.css;
            break;
          }
        }
      } else if (selectorConfig.css) {
        cssSelector = selectorConfig.css;
      }
      
      if (!cssSelector) {
        throw new Error('无法从选择器配置中提取 CSS 选择器');
      }
      
      const isChecked = await this.page.evaluate((sel) => {
        const element = document.querySelector(sel);
        return element && element.checked === true;
      }, cssSelector);
      
      const expectedState = checked === true;
      if (isChecked !== expectedState) {
        throw new Error(`点击后验证失败: 元素 checked 状态为 ${isChecked}，期望 ${expectedState}`);
      }
      
      this.log('debug', `✓ checked 状态验证通过: ${isChecked}`);
    }
  }
  
  /**
   * 等待页面内容变化
   */
  async waitForPageChange(checkSelector, timeout = 15000) {
    this.log('debug', '等待页面变化...');
    
    const startTime = Date.now();
    const initialUrl = this.page.url();
    
    while (Date.now() - startTime < timeout) {
      // 检查 URL 是否变化
      if (this.page.url() !== initialUrl) {
        this.log('debug', '✓ URL 已变化');
        return true;
      }
      
      // 检查特定元素是否出现
      if (checkSelector) {
        const smartSelector = SmartSelector.fromConfig(checkSelector, this.page);
        const newElement = await smartSelector.find(1000);
        if (newElement) {
          this.log('debug', '✓ 页面内容已变化');
          return true;
        }
      }
      
      await new Promise(resolve => setTimeout(resolve, 500));
    }
    
    this.log('warn', '等待页面变化超时');
    return false;
  }
}

module.exports = ClickAction;
