/**
 * HCaptcha 通用自动解决器
 * 
 * 功能：
 * - 自动检测 hCaptcha 元素
 * - 调用多种 Captcha API（YesCaptcha, CapSolver, 2Captcha）
 * - 自动注入 token 并触发回调
 * - 自动点击 checkbox
 * - 等待验证完成
 * - 处理图片挑战
 * 
 * 使用示例：
 * const solver = new HCaptchaSolver({
 *   yescaptcha: yescaptchaAPI,
 *   capsolver: capsolverAPI,
 *   twoCaptcha: twoCaptchaSolver,
 *   logger: logger
 * });
 * 
 * const result = await solver.solve(page, {
 *   timeout: 120000,
 *   waitForToken: true,
 *   handleImageChallenge: true
 * });
 */

const logger = require('../../logger');

class HCaptchaSolver {
  constructor(options = {}) {
    this.yescaptcha = options.yescaptcha;
    this.capsolver = options.capsolver;
    this.twoCaptcha = options.twoCaptcha;
    this.logger = options.logger || logger;
    this.siteName = options.siteName || 'HCaptcha';
  }
  
  /**
   * 检测页面中的 hCaptcha 元素
   * @param {Page} page - Puppeteer Page 实例
   * @returns {Promise<Object|null>} { siteKey, callback, type, element }
   */
  async detectHCaptcha(page) {
    return await page.evaluate(() => {
      // 方法1: 从 div.h-captcha 或 iframe 中获取
      const hcaptchaDiv = document.querySelector('.h-captcha, [data-hcaptcha-response]');
      if (hcaptchaDiv) {
        const siteKey = hcaptchaDiv.getAttribute('data-sitekey');
        const callback = hcaptchaDiv.getAttribute('data-callback');
        if (siteKey) {
          return { 
            siteKey, 
            callback, 
            type: 'div-element',
            found: true
          };
        }
      }
      
      // 方法2: 从 iframe 的 src 中提取
      const iframes = document.querySelectorAll('iframe[src*="hcaptcha"]');
      for (const iframe of iframes) {
        try {
          const src = iframe.src;
          const match = src.match(/sitekey=([^&]+)/);
          if (match) {
            return {
              siteKey: match[1],
              callback: null,
              type: 'iframe-src',
              found: true
            };
          }
        } catch (e) {
          // 继续
        }
      }
      
      // 方法3: 检查 Stripe 的特殊 iframe
      const stripeIframe = document.querySelector('iframe[src*="hcaptcha-inner"]');
      if (stripeIframe) {
        try {
          const src = stripeIframe.src;
          const match = src.match(/sitekey=([^&]+)/);
          if (match) {
            return {
              siteKey: match[1],
              callback: null,
              type: 'stripe-iframe',
              found: true
            };
          }
        } catch (e) {
          // 继续
        }
      }
      
      return null;
    });
  }
  
  /**
   * 获取 hCaptcha token
   * 优先级：YesCaptcha > CapSolver > 2Captcha
   */
  async solveToken(siteKey, pageUrl, options = {}) {
    // 1. 尝试 YesCaptcha
    if (this.yescaptcha && this.yescaptcha.apiKey) {
      try {
        this.logger.info(this.siteName, '  → 使用 YesCaptcha 获取 token...');
        const token = await this.yescaptcha.solveHCaptcha(siteKey, pageUrl, options);
        this.logger.success(this.siteName, `  → ✓ YesCaptcha 成功`);
        return token;
      } catch (error) {
        this.logger.warn(this.siteName, `  → YesCaptcha 失败: ${error.message}`);
      }
    }
    
    // 2. 尝试 CapSolver
    if (this.capsolver && this.capsolver.apiKey) {
      try {
        this.logger.info(this.siteName, '  → 使用 CapSolver 获取 token...');
        const token = await this.capsolver.solveHCaptcha(siteKey, pageUrl);
        this.logger.success(this.siteName, `  → ✓ CapSolver 成功`);
        return token;
      } catch (error) {
        this.logger.warn(this.siteName, `  → CapSolver 失败: ${error.message}`);
      }
    }
    
    throw new Error('所有 Captcha API 都失败了');
  }
  
  /**
   * 注入 token 到页面
   */
  async injectToken(page, token, callback = null) {
    return await page.evaluate((token, callbackName) => {
      try {
        // 设置到隐藏的 textarea
        const textarea = document.querySelector('[name="h-captcha-response"]');
        const textareaG = document.querySelector('[name="g-recaptcha-response"]');
        if (textarea) {
          textarea.value = token;
          textarea.innerHTML = token;
        }
        if (textareaG) {
          textareaG.value = token;
          textareaG.innerHTML = token;
        }
        
        // 执行回调函数
        let callbackExecuted = false;
        
        if (callbackName && typeof window[callbackName] === 'function') {
          window[callbackName](token);
          callbackExecuted = true;
          return { success: true, method: 'custom-callback', callback: callbackName };
        }
        
        if (window.hcaptcha) {
          if (window.hcaptcha.setResponse) {
            window.hcaptcha.setResponse(token);
            callbackExecuted = true;
          }
          
          if (window.hcaptcha.callback && typeof window.hcaptcha.callback === 'function') {
            window.hcaptcha.callback(token);
            return { success: true, method: 'hcaptcha.callback' };
          }
        }
        
        // 触发 change 事件
        if (textarea) {
          const event = new Event('change', { bubbles: true });
          textarea.dispatchEvent(event);
        }
        
        return { success: true, method: 'textarea-only', callbackExecuted };
      } catch (e) {
        return { success: false, error: e.message };
      }
    }, token, callback);
  }
  
  /**
   * 点击 hCaptcha checkbox
   */
  async clickCheckbox(page) {
    try {
      const frames = page.frames();
      let clicked = false;
      
      for (const frame of frames) {
        try {
          const frameUrl = frame.url();
          
          if (frameUrl.includes('hcaptcha') && (frameUrl.includes('checkbox') || frameUrl.includes('anchor'))) {
            this.logger.info(this.siteName, `  → 找到 checkbox frame`);
            
            const checkboxClicked = await frame.evaluate(() => {
              const checkbox = document.querySelector('#checkbox') ||
                              document.querySelector('.check') ||
                              document.querySelector('[type="checkbox"]') ||
                              document.querySelector('[role="checkbox"]');
              
              if (checkbox) {
                checkbox.click();
                return { success: true, type: 'direct-click' };
              }
              
              const clickableElements = document.querySelectorAll('div, span, label');
              for (const el of clickableElements) {
                const rect = el.getBoundingClientRect();
                if (rect.width > 0 && rect.height > 0) {
                  el.click();
                  return { success: true, type: 'fallback-click' };
                }
              }
              
              return { success: false };
            });
            
            if (checkboxClicked.success) {
              this.logger.success(this.siteName, `  → ✓ 已点击 checkbox`);
              clicked = true;
              break;
            }
          }
        } catch (e) {
          // 继续
        }
      }
      
      return { success: clicked };
    } catch (error) {
      return { success: false, error: error.message };
    }
  }
  
  /**
   * 等待验证完成
   */
  async waitForVerification(page, options = {}) {
    const { timeout = 120000, checkInterval = 2000 } = options;
    
    this.logger.info(this.siteName, '  → 等待验证完成...');
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
      const status = await page.evaluate(() => {
        const response = document.querySelector('[name="h-captcha-response"]') || 
                       document.querySelector('[name="g-recaptcha-response"]');
        return response && response.value && response.value.length > 20;
      });
      
      if (status) {
        const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
        this.logger.success(this.siteName, `  → ✓ 验证完成（耗时${elapsed}秒）`);
        return true;
      }
      
      await new Promise(resolve => setTimeout(resolve, checkInterval));
    }
    
    this.logger.error(this.siteName, '  → ✗ 验证超时！');
    return false;
  }
  
  /**
   * 完整的 hCaptcha 解决流程
   */
  async solve(page, options = {}) {
    try {
      // 1. 检测 hCaptcha
      const captchaInfo = await this.detectHCaptcha(page);
      
      if (!captchaInfo || !captchaInfo.found) {
        this.logger.info(this.siteName, '  → 未检测到 hCaptcha');
        return true;
      }
      
      if (!captchaInfo.siteKey) {
        this.logger.warn(this.siteName, '  → 无法获取 siteKey');
        return true;
      }
      
      this.logger.info(this.siteName, `  → 检测到 hCaptcha（${captchaInfo.type}）`);
      
      // 2. 获取 token
      const token = await this.solveToken(captchaInfo.siteKey, page.url(), options);
      
      // 3. 注入 token
      const injected = await this.injectToken(page, token, captchaInfo.callback);
      if (!injected.success) {
        throw new Error(`Token 注入失败: ${injected.error}`);
      }
      this.logger.success(this.siteName, `  → ✓ Token 注入成功`);
      
      // 4. 点击 checkbox（可选）
      if (options.clickCheckbox !== false) {
        await this.clickCheckbox(page);
      }
      
      // 5. 等待验证（可选）
      if (options.waitForVerification !== false) {
        return await this.waitForVerification(page, options);
      }
      
      return true;
    } catch (error) {
      this.logger.error(this.siteName, `  → ✗ 解决失败: ${error.message}`);
      return false;
    }
  }
}

module.exports = HCaptchaSolver;
