/**
 * Windsurf Register - Windsurf网站注册
 * https://windsurf.com/account/register
 * 
 * 注册流程：
 * Step 1: 填写基本信息（First Name, Last Name, Email）
 * Step 2: 设置密码
 * Step 3: 邮箱验证
 * Step 4: 完善个人信息
 * ... 根据实际情况继续添加步骤
 */

const AccountDataGenerator = require('../../../shared/libs/account-generator');
const HumanBehavior = require('../../../shared/libs/browser/human-behavior');
const CloudflareHandler = require('../../../shared/libs/browser/cloudflare-handler');
const logger = require('../../../shared/logger');
const EmailVerificationService = require('../email-verification');
const { DEFAULT_CONFIG } = require('../config');
const CardGenerator = require('../../../shared/libs/card-generator');
const database = require('../../../shared/libs/database');
const CapSolverAPI = require('../../../shared/libs/browser/capsolver-api');
const YesCaptchaAPI = require('../../../shared/libs/browser/yescaptcha-api');
const BrowserManager = require('../../../shared/libs/browser/browser-manager');
const { Solver } = require('2captcha-ts');

class WindsurfRegister {
  constructor(options = {}) {
    this.siteName = 'Windsurf';
    this.siteUrl = 'https://windsurf.com/account/register';
    this.dataGen = new AccountDataGenerator();
    this.human = new HumanBehavior();
    this.emailService = new EmailVerificationService();
    this.capsolver = new CapSolverAPI();
    this.yescaptcha = new YesCaptchaAPI();
    
    // 初始化 2Captcha
    const twoCaptchaKey = process.env.TWOCAPTCHA_API_KEY;
    if (twoCaptchaKey && twoCaptchaKey !== '你的2Captcha_API_KEY') {
      try {
        this.twoCaptchaSolver = new Solver(twoCaptchaKey);
        logger.info(this.siteName, `  → 2Captcha 已初始化 (Key: ${twoCaptchaKey.substring(0, 10)}...)`);
      } catch (error) {
        logger.error(this.siteName, `  → 2Captcha 初始化失败: ${error.message}`);
      }
    }
    
    // 检查 YesCaptcha 配置
    if (this.yescaptcha.apiKey) {
      logger.info(this.siteName, `  → YesCaptcha 已初始化 (Key: ${this.yescaptcha.apiKey.substring(0, 10)}...)`);
    }
    
    // 浏览器管理器（支持多profile并发）
    this.browserManager = new BrowserManager({
      profileId: options.adspowerUserId || process.env.ADSPOWER_USER_ID,
      siteName: this.siteName
    });
    this.browser = null;
    this.page = null;
    this.currentStep = 0;
    this.accountData = null;
    
    // 记录注册时间和额外信息
    this.registrationTime = null;
    this.quotaInfo = null;
    this.billingInfo = null;
    this.cardInfo = null;
    
    // 定义所有步骤
    this.steps = [
      { id: 1, name: '填写基本信息', method: 'step1_fillBasicInfo' },
      { id: 2, name: '设置密码', method: 'step2_setPassword' },
      { id: 3, name: '邮箱验证', method: 'step3_emailVerification' },
      { id: 4, name: '跳过问卷', method: 'step4_skipSurvey' },
      { id: 5, name: '选择计划', method: 'step5_selectPlan' },
      { id: 6, name: '填写支付信息', method: 'step6_fillPayment' },
      { id: 7, name: '获取订阅信息', method: 'step7_getSubscriptionInfo' },
      { id: 8, name: '保存到数据库', method: 'step8_saveToDatabase' },
      { id: 9, name: '清理并关闭浏览器', method: 'step9_clearAndCloseBrowser' },
    ];
  }
  
  /**
   * 获取步骤总数
   */
  getTotalSteps() {
    return this.steps.length;
  }
  
  /**
   * 获取当前步骤信息
   */
  getCurrentStepInfo() {
    if (this.currentStep === 0) {
      return { id: 0, name: '未开始', total: this.getTotalSteps() };
    }
    const step = this.steps[this.currentStep - 1];
    return { 
      ...step, 
      current: this.currentStep, 
      total: this.getTotalSteps() 
    };
  }

  /**
   * 通用方法：等待按钮激活并点击，然后等待页面内容变化
   * @param {Object} options - 配置选项
   * @param {string} options.buttonText - 按钮文本（用于识别，如'Continue'）
   * @param {Function} options.checkContentChanged - 检查页面内容是否已变化的函数，返回Promise<boolean>
   * @param {number} options.waitButtonTimeout - 等待按钮激活的超时时间（毫秒），默认30000
   * @param {number} options.waitContentTimeout - 等待内容变化的超时时间（毫秒），默认15000
   * @param {string} options.actionName - 操作名称（用于日志）
   * @returns {Promise<boolean>} - 是否成功完成
   */
  async clickButtonAndWaitForPageChange(options) {
    const {
      buttonText = 'Continue',
      checkContentChanged,
      waitButtonTimeout = 30000,
      waitContentTimeout = 15000,
      actionName = '点击按钮'
    } = options;
    
    try {
      // 阶段1: 等待按钮变为可点击状态（enabled）
      logger.info(this.siteName, `  → 等待"${buttonText}"按钮激活...`);
      
      const buttonStartTime = Date.now();
      let buttonEnabled = false;
      
      while (Date.now() - buttonStartTime < waitButtonTimeout) {
        buttonEnabled = await this.page.evaluate((btnText) => {
          const buttons = Array.from(document.querySelectorAll('button'));
          const targetButton = buttons.find(btn => 
            btn.textContent.trim() === btnText && !btn.disabled
          );
          return !!targetButton;
        }, buttonText);
        
        if (buttonEnabled) {
          const elapsed = ((Date.now() - buttonStartTime) / 1000).toFixed(1);
          logger.success(this.siteName, `  → ✓ 按钮已激活 (耗时: ${elapsed}秒)`);
          break;
        }
        
        // 每5秒输出一次进度
        const elapsed = Date.now() - buttonStartTime;
        if (elapsed > 0 && elapsed % 5000 === 0) {
          logger.info(this.siteName, `  → 等待按钮激活中... 已用时 ${(elapsed/1000).toFixed(0)}秒`);
        }
        
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
      
      if (!buttonEnabled) {
        logger.error(this.siteName, `  → ⚠️ 等待${waitButtonTimeout/1000}秒后按钮仍未激活`);
        return false;
      }
      
      // 阶段2: 点击按钮
      logger.info(this.siteName, `  → ${actionName}...`);
      await this.human.humanClick(this.page, `button:not([disabled])`);
      await this.human.randomDelay(1000, 2000);
      
      // 阶段3: 等待页面内容变化
      logger.info(this.siteName, `  → 等待页面内容变化...`);
      
      const contentStartTime = Date.now();
      let contentChanged = false;
      
      while (Date.now() - contentStartTime < waitContentTimeout) {
        contentChanged = await checkContentChanged();
        
        if (contentChanged) {
          const elapsed = ((Date.now() - contentStartTime) / 1000).toFixed(1);
          logger.success(this.siteName, `  → ✓ 页面内容已变化 (耗时: ${elapsed}秒)`);
          break;
        }
        
        await new Promise(resolve => setTimeout(resolve, 500));
      }
      
      if (!contentChanged) {
        logger.warn(this.siteName, `  → ⚠️ 等待${waitContentTimeout/1000}秒后页面内容未变化`);
        return false;
      }
      
      return true;
      
    } catch (error) {
      logger.error(this.siteName, `  → ${actionName}失败: ${error.message}`);
      return false;
    }
  }

  /**
   * 生成账号数据（干运行模式）
   */
  generateData(options = {}) {
    logger.info(this.siteName, '生成账号数据...');
    
    const account = this.dataGen.generateAccount({
      name: options.name,
      email: options.email,
      username: options.username,
      password: {
        strategy: options.passwordStrategy || 'email',
        ...options.password
      },
      includePhone: false  // Windsurf第一步不需要手机号
    });

    return account;
  }

  /**
   * 初始化浏览器
   */
  async initBrowser() {
    const result = await this.browserManager.launch();
    this.browser = result.browser;
    this.page = result.page;
    
    logger.info(this.siteName, '等待浏览器完全准备...');
    await this.human.randomDelay(2000, 3000);
  }

  /**
   * 关闭浏览器
   */
  async closeBrowser() {
    await this.browserManager.close();
  }

  /**
   * 步骤1: 填写基本信息
   */
  async step1_fillBasicInfo() {
    logger.info(this.siteName, `[步骤 1/${this.getTotalSteps()}] 填写基本信息`);
    
    const overallStartTime = Date.now();
    const overallMaxWait = 180000; // 总共最多重试3分钟
    let stepCompleted = false;
    let retryCount = 0;
    
    while (!stepCompleted && (Date.now() - overallStartTime < overallMaxWait)) {
      try {
        if (retryCount > 0) {
          logger.info(this.siteName, `  → 第 ${retryCount + 1} 次尝试...`);
        }
        
        // 打开注册页面
        logger.info(this.siteName, `打开注册页面: ${this.siteUrl}`);
        await this.page.goto(this.siteUrl, {
          waitUntil: 'networkidle2',
          timeout: 30000
        });
        
        // 模拟阅读页面（1-3秒）
        await this.human.readPage(1, 3);

        // 填写First Name（使用人类行为）
        logger.info(this.siteName, '  → 填写First Name...');
        await this.page.waitForSelector('#firstName', { timeout: 10000 });
        await this.human.humanType(this.page, '#firstName', this.accountData.firstName);

        // 填写Last Name
        logger.info(this.siteName, '  → 填写Last Name...');
        await this.page.waitForSelector('#lastName', { timeout: 10000 });
        await this.human.humanType(this.page, '#lastName', this.accountData.lastName);

        // 填写Email
        logger.info(this.siteName, '  → 填写Email...');
        await this.page.waitForSelector('#email', { timeout: 10000 });
        await this.human.humanType(this.page, '#email', this.accountData.email);

        // 勾选同意条款（如果有）
        try {
          const checkbox = await this.page.$('input[type="checkbox"]');
          if (checkbox) {
            logger.info(this.siteName, '  → 勾选同意条款...');
            await this.human.humanCheckbox(this.page, 'input[type="checkbox"]');
          }
        } catch (error) {
          logger.warn(this.siteName, '  → 未找到同意条款checkbox，跳过');
        }

        // 点击Continue按钮并等待跳转到密码页面
        const success = await this.clickButtonAndWaitForPageChange({
          buttonText: 'Continue',
          checkContentChanged: async () => {
            // 检查是否有密码输入框（表示已进入下一步）
            return await this.page.evaluate(() => {
              return !!document.querySelector('#password');
            });
          },
          waitButtonTimeout: 30000,
          waitContentTimeout: 15000,
          actionName: '点击Continue进入密码设置页面'
        });
        
        if (!success) {
          logger.warn(this.siteName, '  → ⚠️ 未能进入密码页面，将重新尝试');
          retryCount++;
          await this.human.randomDelay(2000, 3000);
          continue;
        }
        
        // 成功完成
        stepCompleted = true;
        
      } catch (error) {
        logger.warn(this.siteName, `  → 执行出错: ${error.message}，将重新尝试`);
        retryCount++;
        await this.human.randomDelay(3000, 5000);
        continue;
      }
    }
    
    if (!stepCompleted) {
      logger.error(this.siteName, `  → ✗ 步骤1失败：${retryCount + 1}次尝试后仍未成功`);
      throw new Error(`步骤1：${retryCount + 1}次尝试后仍未能完成基本信息填写`);
    }
    
    // 额外等待确保页面稳定
    await this.human.randomDelay(1000, 2000);
    
    this.currentStep = 1;
    logger.success(this.siteName, `步骤 1 完成 (共尝试 ${retryCount + 1} 次)`);
  }

  /**
   * 步骤2: 设置密码
   */
  async step2_setPassword() {
    logger.info(this.siteName, `[步骤 2/${this.getTotalSteps()}] 设置密码`);
    
    // 等待密码页面加载
    await this.human.readPage(1, 2);
    
    // 填写密码
    logger.info(this.siteName, '  → 填写密码...');
    await this.page.waitForSelector('#password', { timeout: 10000 });
    
    // 先清空密码框
    await this.page.evaluate(() => {
      const elem = document.querySelector('#password');
      if (elem) elem.value = '';
    });
    
    await this.human.humanType(this.page, '#password', this.accountData.password);
    
    // 填写确认密码
    logger.info(this.siteName, '  → 填写确认密码...');
    await this.page.waitForSelector('#passwordConfirmation', { timeout: 10000 });
    
    // 先清空确认密码框（防止有残留）
    await this.page.evaluate(() => {
      const elem = document.querySelector('#passwordConfirmation');
      if (elem) elem.value = '';
    });
    
    await this.human.humanType(this.page, '#passwordConfirmation', this.accountData.password);
    
    // 等待密码验证
    logger.info(this.siteName, '  → 等待密码验证...');
    await this.human.randomDelay(1000, 2000);
    
    // 查找并点击Continue按钮（此时会进入 Cloudflare Turnstile 验证页面）
    logger.info(this.siteName, '  → 点击Continue按钮...');
    
    try {
      // 等待按钮可点击
      await this.page.waitForFunction(
        () => {
          const button = document.querySelector('button');
          if (!button) return false;
          const text = button.textContent.trim();
          return text === 'Continue' && !button.disabled;
        },
        { timeout: 20000 }
      );
      
      logger.info(this.siteName, '  → 按钮已激活，点击进入验证页面...');
      
      // 点击按钮
      await Promise.all([
        this.page.waitForNavigation({ waitUntil: 'load', timeout: 10000 }).catch(() => {}),
        this.human.humanClick(this.page, 'button:not([disabled])')
      ]);
      
      logger.success(this.siteName, '  → 已进入 Cloudflare Turnstile 验证页面');
      
    } catch (error) {
      logger.warn(this.siteName, '  → 按钮等待超时，尝试按Enter键');
      await this.page.keyboard.press('Enter');
    }
    
    // 等待页面稳定
    await this.human.randomDelay(1000, 2000);
    
    // 等待 Cloudflare Turnstile 验证完成（手动或其他方式）
    logger.info(this.siteName, '  → 等待 Cloudflare Turnstile 验证...');
    logger.info(this.siteName, '  → 请手动完成验证或等待自动处理...');
    
    const startTime = Date.now();
    const maxWait = 120000; // 最多等待120秒
    
    // 轮询检查按钮是否激活
    while (Date.now() - startTime < maxWait) {
      const buttonEnabled = await this.page.evaluate(() => {
        const button = document.querySelector('button');
        return button && !button.disabled && button.textContent.trim() === 'Continue';
      });
      
      if (buttonEnabled) {
        const duration = ((Date.now() - startTime) / 1000).toFixed(1);
        logger.success(this.siteName, `  → ✓ Turnstile 验证完成！耗时: ${duration}秒`);
        break;
      }
      
      // 每10秒输出一次进度
      const elapsed = Date.now() - startTime;
      if (elapsed > 0 && elapsed % 10000 === 0) {
        logger.info(this.siteName, `  → 等待验证中... 已用时 ${elapsed/1000}秒`);
      }
      
      await new Promise(resolve => setTimeout(resolve, 500));
    }
    
    if (Date.now() - startTime >= maxWait) {
      logger.error(this.siteName, '  → ⚠️ 验证超时（120秒）');
      throw new Error('Turnstile 验证超时');
    }
    
    // 点击 Continue 进入邮箱验证
    logger.info(this.siteName, '  → 点击Continue进入邮箱验证...');
    await Promise.all([
      this.page.waitForNavigation({ waitUntil: 'load', timeout: 10000 }).catch(() => {}),
      this.human.humanClick(this.page, 'button:not([disabled])')
    ]);
    
    // 额外等待确保页面稳定
    await this.human.randomDelay(1000, 2000);
    
    this.currentStep = 2;
    logger.success(this.siteName, `步骤 2 完成`);
  }

  /**
   * 步骤3: 邮箱验证
   */
  async step3_emailVerification() {
    logger.info(this.siteName, `[步骤 3/${this.getTotalSteps()}] 邮箱验证`);
    
    // Cloudflare Turnstile 验证已在步骤2中完成
    logger.info(this.siteName, '  → Turnstile 验证已通过，开始邮箱验证...');
    
    try {
      // 等待验证码页面加载
      await this.human.readPage(1, 2);
      
      // 延迟2秒后再获取验证码，让邮件有足够时间到达
      logger.info(this.siteName, '  → 延迟2秒，等待邮件到达...');
      await new Promise(resolve => setTimeout(resolve, 2000));
      
      // 获取验证码（从邮箱）
      logger.info(this.siteName, '  → 正在从邮箱获取验证码...');
      logger.info(this.siteName, `  → 接收邮箱: ${this.accountData.email}`);
      logger.info(this.siteName, '  → 注意：如果长时间无响应，请检查：');
      logger.info(this.siteName, '    1. 邮件是否已发送到邮箱');
      logger.info(this.siteName, '    2. QQ邮箱IMAP配置是否正确');
      logger.info(this.siteName, '    3. 邮件是否被标记为垃圾邮件');
      
      const code = await this.emailService.getVerificationCode(
        'windsurf',
        this.accountData.email,
        120  // 增加到120秒超时
      );
      
      logger.success(this.siteName, `  → ✓ 验证码: ${code}`);
      
      // 等待验证码输入框加载
      await this.human.randomDelay(2000, 3000);
      
      // Windsurf使用6个独立的输入框，需要逐个填写
      logger.info(this.siteName, '  → 查找验证码输入框...');
      
      // 等待输入框出现
      await this.page.waitForSelector('input[type="text"]', { timeout: 10000 });
      
      // 获取所有文本输入框
      const inputs = await this.page.$$('input[type="text"]');
      logger.info(this.siteName, `  → 找到 ${inputs.length} 个输入框`);
      
      if (inputs.length >= 6 && code.length === 6) {
        // 逐个填写每一位验证码
        logger.info(this.siteName, '  → 填写6位验证码...');
        for (let i = 0; i < 6; i++) {
          const char = code[i].toUpperCase(); // 确保大写
          
          // 点击输入框获取焦点
          await inputs[i].click();
          await this.human.randomDelay(100, 200);
          
          // 输入字符
          await inputs[i].type(char);
          await this.human.randomDelay(300, 500);
          
          logger.info(this.siteName, `  → 已输入第 ${i + 1} 位: ${char}`);
        }
        logger.success(this.siteName, '  → 验证码已填写完成');
        
        // 输入完6位验证码后，页面会自动提交
        logger.info(this.siteName, '  → 等待邮箱验证完成并跳转到问卷页面...');
        logger.info(this.siteName, '  → 将持续等待直到跳转成功（无时间限制）...');
        
        // 无限等待页面跳转到 /account/onboarding?page=source
        const startTime = Date.now();
        let registrationComplete = false;
        let hasClickedButton = false;
        
        while (!registrationComplete) {
          const currentUrl = this.page.url();
          
          // 检查1: 页面是否已经跳转成功（自动跳转成功）
          if (currentUrl.includes('/account/onboarding') && currentUrl.includes('page=source')) {
            registrationComplete = true;
            const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
            logger.success(this.siteName, `  → ✓ 邮箱验证成功！已跳转到问卷页面 (耗时: ${totalTime}秒)`);
            logger.info(this.siteName, `  → 当前页面: ${currentUrl}`);
            break;
          }
          
          // 检查2: 页面按钮是否变为激活状态（自动跳转失败，需要手动点击）
          if (!hasClickedButton) {
            const buttonEnabled = await this.page.evaluate(() => {
              const buttons = Array.from(document.querySelectorAll('button'));
              const continueButton = buttons.find(btn => 
                btn.textContent.trim() === 'Continue' && !btn.disabled
              );
              return !!continueButton;
            });
            
            if (buttonEnabled) {
              const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
              logger.warn(this.siteName, `  → ⚠️ 检测到按钮重新激活 (${elapsed}秒后)`);
              logger.info(this.siteName, '  → 自动跳转可能失败，尝试手动点击按钮...');
              
              try {
                // 点击 Continue 按钮
                await this.human.humanClick(this.page, 'button:not([disabled])');
                hasClickedButton = true;
                logger.success(this.siteName, '  → ✓ 已点击按钮，继续等待跳转...');
                await this.human.randomDelay(1000, 2000);
              } catch (e) {
                logger.warn(this.siteName, `  → 点击按钮失败: ${e.message}`);
              }
            }
          }
          
          // 每5秒输出一次进度
          const elapsed = Date.now() - startTime;
          if (elapsed > 0 && elapsed % 5000 === 0) {
            logger.info(this.siteName, `  → 等待中... 已用时 ${(elapsed/1000).toFixed(0)}秒`);
          }
          
          await new Promise(resolve => setTimeout(resolve, 500));
        }
        
        // 额外等待页面稳定
        await this.human.randomDelay(2000, 3000);
        
        this.currentStep = 3;
        logger.success(this.siteName, `步骤 3 完成 - 账号创建成功`);
        
      } else {
        logger.error(this.siteName, '  → 未找到验证码输入框！');
        logger.warn(this.siteName, '  → 请手动输入验证码: ' + code);
        
        // 等待用户手动输入
        await this.human.randomDelay(30000, 30000);
        
        this.currentStep = 3;
      }
      
    } catch (error) {
      logger.error(this.siteName, `邮箱验证失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 步骤4: 跳过问卷调查
   */
  async step4_skipSurvey() {
    logger.info(this.siteName, `[步骤 4/${this.getTotalSteps()}] 跳过问卷`);
    
    const overallStartTime = Date.now();
    const overallMaxWait = 120000; // 总共最多重试2分钟
    let stepCompleted = false;
    let retryCount = 0;
    
    while (!stepCompleted && (Date.now() - overallStartTime < overallMaxWait)) {
      try {
        if (retryCount > 0) {
          logger.info(this.siteName, `  → 第 ${retryCount + 1} 次尝试...`);
        }
        
        // 等待页面加载
        await this.human.readPage(2, 3);
        
        logger.info(this.siteName, '  → 查找"Skip this step"按钮...');
        
        const startTime = Date.now();
        const maxWait = 30000; // 单次查找最多等待30秒
        let skipButton = null;
        let buttonFound = false;
        
        // 轮询查找按钮
        while (!buttonFound && (Date.now() - startTime < maxWait)) {
          try {
            // 查找所有按钮或链接
            const buttons = await this.page.$$('button, a');
            
            for (const button of buttons) {
              const text = await this.page.evaluate(el => el.textContent?.trim(), button);
              // 匹配 "Skip this step" 或 "skip"
              if (text && (text.toLowerCase().includes('skip this step') || text.toLowerCase() === 'skip')) {
                skipButton = button;
                buttonFound = true;
                logger.success(this.siteName, `  → ✓ 找到按钮: "${text}" (耗时: ${((Date.now() - startTime) / 1000).toFixed(1)}秒)`);
                break;
              }
            }
            
            if (buttonFound) {
              break;
            }
            
            // 每5秒输出一次进度
            const elapsed = Date.now() - startTime;
            if (elapsed > 0 && elapsed % 5000 === 0) {
              logger.info(this.siteName, `  → 等待按钮出现... 已用时 ${elapsed/1000}秒`);
            }
            
            // 等待2秒后继续查找
            await new Promise(resolve => setTimeout(resolve, 2000));
            
          } catch (error) {
            logger.warn(this.siteName, `  → 查找按钮时出错: ${error.message}，继续尝试...`);
            await new Promise(resolve => setTimeout(resolve, 2000));
          }
        }
        
        if (skipButton && buttonFound) {
          logger.info(this.siteName, '  → 点击"Skip this step"按钮...');
          
          // 直接点击找到的按钮元素
          await skipButton.click();
          logger.success(this.siteName, '  → ✓ 已点击按钮');
          
          // 等待页面跳转到 /account/upgrade-prompt
          logger.info(this.siteName, '  → 等待跳转到 /account/upgrade-prompt 页面...');
          
          const jumpStartTime = Date.now();
          const jumpMaxWait = 15000; // 最多等待15秒
          let jumpSuccess = false;
          
          while (Date.now() - jumpStartTime < jumpMaxWait) {
            const newUrl = this.page.url();
            
            // 必须跳转到 upgrade-prompt 页面
            if (newUrl.includes('/account/upgrade-prompt')) {
              jumpSuccess = true;
              stepCompleted = true;
              logger.success(this.siteName, `  → ✓ 成功跳转到计划选择页面`);
              logger.info(this.siteName, `  → 当前页面: ${newUrl}`);
              break;
            }
            
            await new Promise(resolve => setTimeout(resolve, 500));
          }
          
          if (!jumpSuccess) {
            const finalUrl = this.page.url();
            logger.warn(this.siteName, `  → ⚠️ 未跳转到升级页面，将重新尝试`);
            logger.warn(this.siteName, `  → 当前页面: ${finalUrl}`);
            retryCount++;
            await this.human.randomDelay(2000, 3000);
            continue; // 重新开始循环
          }
          
        } else {
          // 未找到按钮，重试
          logger.warn(this.siteName, `  → ⚠️ 未找到Skip按钮，将重新尝试`);
          retryCount++;
          await this.human.randomDelay(2000, 3000);
          continue;
        }
        
      } catch (error) {
        logger.warn(this.siteName, `  → 执行出错: ${error.message}，将重新尝试`);
        retryCount++;
        await this.human.randomDelay(2000, 3000);
        continue;
      }
    }
    
    if (!stepCompleted) {
      const currentUrl = this.page.url();
      logger.error(this.siteName, `  → ✗ 步骤4失败：${retryCount + 1}次尝试后仍未成功`);
      logger.error(this.siteName, `  → 当前页面: ${currentUrl}`);
      throw new Error(`步骤4：${retryCount + 1}次尝试后仍未成功跳转到 /account/upgrade-prompt 页面`);
    }
    
    // 额外等待页面稳定
    await this.human.randomDelay(2000, 3000);
    
    this.currentStep = 4;
    logger.success(this.siteName, `步骤 4 完成 (共尝试 ${retryCount + 1} 次)`);
  }

  /**
   * 步骤5: 选择计划
   */
  async step5_selectPlan() {
    logger.info(this.siteName, `[步骤 5/${this.getTotalSteps()}] 选择计划`);
    
    const overallStartTime = Date.now();
    const overallMaxWait = 120000; // 总共最多重试2分钟
    let stepCompleted = false;
    let retryCount = 0;
    
    while (!stepCompleted && (Date.now() - overallStartTime < overallMaxWait)) {
      try {
        if (retryCount > 0) {
          logger.info(this.siteName, `  → 第 ${retryCount + 1} 次尝试...`);
        }
        
        // 等待页面加载
        await this.human.readPage(2, 3);
        
        logger.info(this.siteName, '  → 查找计划选择按钮...');
        
        const startTime = Date.now();
        const maxWait = 30000; // 单次查找最多等待30秒
        let selectButton = null;
        let buttonFound = false;
        
        // 轮询查找按钮
        while (!buttonFound && (Date.now() - startTime < maxWait)) {
          try {
            const buttons = await this.page.$$('button, a');
            
            for (const button of buttons) {
              const text = await this.page.evaluate(el => el.textContent?.trim(), button);
              // 匹配多种可能的按钮文本
              if (text && (
                text.toLowerCase().includes('select plan') ||
                text.toLowerCase().includes('continue') ||
                text.toLowerCase().includes('get started') ||
                text.toLowerCase() === 'select'
              )) {
                selectButton = button;
                buttonFound = true;
                logger.success(this.siteName, `  → ✓ 找到按钮: "${text}" (耗时: ${((Date.now() - startTime) / 1000).toFixed(1)}秒)`);
                break;
              }
            }
            
            if (buttonFound) {
              break;
            }
            
            // 每5秒输出一次进度
            const elapsed = Date.now() - startTime;
            if (elapsed > 0 && elapsed % 5000 === 0) {
              logger.info(this.siteName, `  → 等待按钮出现... 已用时 ${elapsed/1000}秒`);
            }
            
            await new Promise(resolve => setTimeout(resolve, 2000));
            
          } catch (error) {
            logger.warn(this.siteName, `  → 查找按钮时出错: ${error.message}，继续尝试...`);
            await new Promise(resolve => setTimeout(resolve, 2000));
          }
        }
        
        if (selectButton && buttonFound) {
          logger.info(this.siteName, '  → 点击计划选择按钮...');
          
          // 直接点击找到的按钮元素
          await selectButton.click();
          logger.success(this.siteName, '  → ✓ 已点击按钮');
          
          // 等待页面跳转到 Stripe checkout
          logger.info(this.siteName, '  → 等待跳转到 Stripe 支付页面...');
          
          const jumpStartTime = Date.now();
          const jumpMaxWait = 20000; // 最多等待20秒
          let jumpSuccess = false;
          
          while (Date.now() - jumpStartTime < jumpMaxWait) {
            const newUrl = this.page.url();
            
            // 必须跳转到 Stripe checkout
            if (newUrl.includes('checkout.stripe.com') || newUrl.includes('stripe.com')) {
              jumpSuccess = true;
              stepCompleted = true;
              logger.success(this.siteName, `  → ✓ 成功跳转到 Stripe 支付页面`);
              logger.info(this.siteName, `  → 当前页面: ${newUrl}`);
              break;
            }
            
            await new Promise(resolve => setTimeout(resolve, 500));
          }
          
          if (!jumpSuccess) {
            const finalUrl = this.page.url();
            logger.warn(this.siteName, `  → ⚠️ 未跳转到支付页面，将重新尝试`);
            logger.warn(this.siteName, `  → 当前页面: ${finalUrl}`);
            retryCount++;
            await this.human.randomDelay(2000, 3000);
            continue;
          }
          
        } else {
          // 未找到按钮，重试
          logger.warn(this.siteName, `  → ⚠️ 未找到计划选择按钮，将重新尝试`);
          retryCount++;
          await this.human.randomDelay(2000, 3000);
          continue;
        }
        
      } catch (error) {
        logger.warn(this.siteName, `  → 执行出错: ${error.message}，将重新尝试`);
        retryCount++;
        await this.human.randomDelay(2000, 3000);
        continue;
      }
    }
    
    if (!stepCompleted) {
      const currentUrl = this.page.url();
      logger.error(this.siteName, `  → ✗ 步骤5失败：${retryCount + 1}次尝试后仍未成功`);
      logger.error(this.siteName, `  → 当前页面: ${currentUrl}`);
      throw new Error(`步骤5：${retryCount + 1}次尝试后仍未成功跳转到 Stripe 支付页面`);
    }
    
    // 额外等待页面稳定
    await this.human.randomDelay(2000, 3000);
    
    this.currentStep = 5;
    logger.success(this.siteName, `步骤 5 完成 (共尝试 ${retryCount + 1} 次)`);
  }

  /**
   * 彻底清空输入框（通过DOM直接操作）
   */
  async clearInputField(selector) {
    try {
      // 方法1: 通过 DOM 清空
      await this.page.evaluate((sel) => {
        const field = document.querySelector(sel);
        if (field) {
          // 聚焦
          field.focus();
          // 全选
          field.select();
          // 清空
          field.value = '';
          // 触发所有相关事件
          field.dispatchEvent(new Event('input', { bubbles: true }));
          field.dispatchEvent(new Event('change', { bubbles: true }));
          field.dispatchEvent(new Event('blur', { bubbles: true }));
          field.blur();
        }
      }, selector);
      
      // 方法2: 使用 Puppeteer API 进一步清理
      const field = await this.page.$(selector);
      if (field) {
        await field.click({ clickCount: 3 }); // 三击全选
        await this.page.keyboard.press('Backspace');
        await this.human.randomDelay(100, 200);
      }
    } catch (e) {
      logger.warn(this.siteName, `  → 清空输入框失败 (${selector}): ${e.message}`);
    }
  }
  
  /**
   * 填写银行卡表单（每次都彻底清空后重新填写）
   * @returns {boolean} 是否成功填写
   */
  async fillCardForm(card, isRetry = false) {
    if (!isRetry) {
      // 首次填写：选择支付方式
      logger.info(this.siteName, '  → 选择银行卡支付方式...');
      const cardRadio = await this.page.$('input[type="radio"][value="card"]');
      if (cardRadio) {
        await cardRadio.click();
        logger.success(this.siteName, '  → ✓ 已点击银行卡选项');
        await this.human.randomDelay(3000, 5000);
        
        try {
          await this.page.waitForFunction(
            () => {
              const cardNumber = document.querySelector('#cardNumber');
              const cardExpiry = document.querySelector('#cardExpiry');
              const cardCvc = document.querySelector('#cardCvc');
              const billingName = document.querySelector('#billingName');
              return cardNumber && cardExpiry && cardCvc && billingName;
            },
            { timeout: 30000 }
          );
          logger.success(this.siteName, '  → ✓ 支付表单加载完成');
        } catch (e) {
          logger.warn(this.siteName, `  → 等待表单超时: ${e.message}`);
          // 尝试截图调试
          try {
            const screenshot = `/tmp/stripe-form-timeout-${Date.now()}.png`;
            await this.page.screenshot({ path: screenshot });
            logger.info(this.siteName, `  → 调试截图: ${screenshot}`);
          } catch (err) {}
        }
      }
    }
    
    // ===== 填写卡号 =====
    logger.info(this.siteName, `  → 填写卡号: ${card.number}...`);
    
    // 0. 先确认元素存在
    try {
      await this.page.waitForSelector('#cardNumber', { timeout: 10000 });
    } catch (e) {
      logger.error(this.siteName, `  → ✗ 卡号输入框未找到，可能支付表单未加载: ${e.message}`);
      return false;
    }
    
    // 1. 彻底清空卡号
    await this.clearInputField('#cardNumber');
    await this.human.randomDelay(300, 500);
    
    // 2. 点击并聚焦
    const cardNumberField = await this.page.$('#cardNumber');
    if (!cardNumberField) {
      logger.error(this.siteName, '  → ✗ 卡号输入框消失，页面可能已变化');
      return false;
    }
    await cardNumberField.click();
    await this.human.randomDelay(300, 500);
    
    // 3. 再次确保清空（按多次 Backspace）
    for (let i = 0; i < 25; i++) {
      await this.page.keyboard.press('Backspace');
    }
    await this.human.randomDelay(300, 500);
    
    // 4. 填写新卡号
    await this.page.type('#cardNumber', card.number, { delay: 100 });
    await this.human.randomDelay(500, 800);
    logger.success(this.siteName, '  → ✓ 卡号已填写');
    
    // ===== 填写有效期 =====
    const expiry = `${card.month}${card.year}`;
    logger.info(this.siteName, `  → 填写有效期: ${card.month}/${card.year}...`);
    
    // 1. 彻底清空
    await this.clearInputField('#cardExpiry');
    await this.human.randomDelay(200, 300);
    
    // 2. 点击并聚焦
    const cardExpiryField = await this.page.$('#cardExpiry');
    if (!cardExpiryField) {
      logger.error(this.siteName, '  → ✗ 有效期输入框未找到');
      return false;
    }
    await cardExpiryField.click();
    await this.human.randomDelay(200, 300);
    
    // 3. 再次确保清空
    for (let i = 0; i < 10; i++) {
      await this.page.keyboard.press('Backspace');
    }
    await this.human.randomDelay(300, 500);
    
    // 4. 填写新有效期
    await this.page.type('#cardExpiry', expiry, { delay: 100 });
    await this.human.randomDelay(500, 800);
    logger.success(this.siteName, '  → ✓ 有效期已填写');
    
    // ===== 填写CVC =====
    logger.info(this.siteName, `  → 填写CVC: ${card.cvv}...`);
    
    // 1. 彻底清空
    await this.clearInputField('#cardCvc');
    await this.human.randomDelay(200, 300);
    
    // 2. 点击并聚焦
    const cardCvcField = await this.page.$('#cardCvc');
    if (!cardCvcField) {
      logger.error(this.siteName, '  → ✗ CVC输入框未找到');
      return false;
    }
    await cardCvcField.click();
    await this.human.randomDelay(200, 300);
    
    // 3. 再次确保清空
    for (let i = 0; i < 10; i++) {
      await this.page.keyboard.press('Backspace');
    }
    await this.human.randomDelay(300, 500);
    
    // 4. 填写新CVC
    await this.page.type('#cardCvc', card.cvv, { delay: 100 });
    await this.human.randomDelay(500, 800);
    logger.success(this.siteName, '  → ✓ CVC已填写');
    
    // ===== 首次填写：持卡人姓名和地址 =====
    if (!isRetry) {
      logger.info(this.siteName, '  → 填写持卡人姓名...');
      await this.clearInputField('#billingName');
      const billingNameField = await this.page.$('#billingName');
      if (!billingNameField) {
        logger.error(this.siteName, '  → ✗ 持卡人姓名输入框未找到');
        return false;
      }
      await billingNameField.click();
      await this.human.randomDelay(300, 500);
      const fullName = `${this.accountData.firstName} ${this.accountData.lastName}`;
      await this.page.type('#billingName', fullName, { delay: 100 });
      
      logger.info(this.siteName, '  → 选择地址：中国澳门特别行政区...');
      await this.page.select('#billingCountry', 'MO');
      await this.human.randomDelay(1000, 2000);
      
      const addressFields = await this.page.$$('input[placeholder*="地址"]');
      if (addressFields.length > 0) {
        logger.info(this.siteName, '  → 填写地址信息...');
        await addressFields[0].type('Macau', { delay: 100 });
        if (addressFields[1]) {
          await this.human.randomDelay(300, 500);
          await addressFields[1].type('Macao', { delay: 100 });
        }
      }
    }
    
    logger.success(this.siteName, '  → ✓ 银行卡信息填写完成');
    return true;
  }
  
  /**
   * 处理 hCaptcha 验证码（使用 CapSolver API 自动识别）
   */
  async handleHCaptcha() {
    // 获取 captcha 信息（支持 Stripe iframe 和标准 hCaptcha）
    const captchaInfo = await this.page.evaluate(() => {
      // 方式1: Stripe 的 hCaptcha iframe
      const stripeFrame = document.querySelector('iframe[src*="hcaptcha-inner"]');
      if (stripeFrame) {
        try {
          const url = new URL(stripeFrame.src);
          const hash = url.hash.substring(1);
          const params = new URLSearchParams(hash);
          const sitekey = params.get('sitekey');
          
          if (sitekey) {
            return {
              type: 'stripe-iframe',
              siteKey: sitekey,
              callback: null,
              containerId: null
            };
          }
        } catch (e) {
          // 继续尝试其他方式
        }
      }
      
      // 方式2: 标准的 hCaptcha
      const hcaptchaDiv = document.querySelector('.h-captcha');
      if (hcaptchaDiv) {
        return {
          type: 'standard',
          siteKey: hcaptchaDiv.getAttribute('data-sitekey'),
          callback: hcaptchaDiv.getAttribute('data-callback'),
          containerId: hcaptchaDiv.id || hcaptchaDiv.getAttribute('data-hcaptcha-widget-id')
        };
      }
      
      // 方式3: hcaptcha.com iframe
      const hcaptchaFrame = document.querySelector('iframe[src*="hcaptcha.com"]');
      if (hcaptchaFrame) {
        return {
          type: 'iframe',
          siteKey: null,
          callback: null,
          containerId: null
        };
      }
      
      return null;
    });
    
    if (!captchaInfo) {
      logger.info(this.siteName, '  → 未检测到 hCaptcha，跳过');
      return true;
    }
    
    logger.info(this.siteName, `  → 检测到 hCaptcha（类型: ${captchaInfo.type}）`);
    
    if (!captchaInfo.siteKey) {
      logger.warn(this.siteName, '  → 无法获取 siteKey，跳过自动识别');
      return true;
    }
    
    // 优先尝试使用 YesCaptcha API
    if (this.yescaptcha.apiKey) {
      try {
        logger.info(this.siteName, '  → 使用 YesCaptcha API 自动识别...');
        
        logger.info(this.siteName, `  → SiteKey: ${captchaInfo.siteKey}`);
        const currentUrl = this.page.url();
        logger.info(this.siteName, `  → 页面 URL: ${currentUrl.substring(0, 80)}...`);
        
        // 调用 YesCaptcha API
        const token = await this.yescaptcha.solveHCaptcha(captchaInfo.siteKey, currentUrl, {
          isInvisible: true  // Stripe 使用 invisible hCaptcha
        });
        
        logger.info(this.siteName, `  → ✓ 获取到 token: ${token.substring(0, 30)}...`);
        
        // 3. 注入 token 并触发回调（按正确顺序）
        const injected = await this.page.evaluate((token, callbackName) => {
          try {
            // 步骤1: 设置到隐藏的 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;
            }
            
            // 步骤2: 执行回调函数（关键！）
            let callbackExecuted = false;
            
            // 方法A: 触发自定义回调（优先级最高）
            if (callbackName && typeof window[callbackName] === 'function') {
              window[callbackName](token);
              callbackExecuted = true;
              return { success: true, method: 'custom-callback', callback: callbackName };
            }
            
            // 方法B: 使用 hcaptcha API 的 setResponse + callback
            if (window.hcaptcha) {
              if (window.hcaptcha.setResponse) {
                window.hcaptcha.setResponse(token);
                callbackExecuted = true;
              }
              
              // 触发 hcaptcha 的回调
              if (window.hcaptcha.callback && typeof window.hcaptcha.callback === 'function') {
                window.hcaptcha.callback(token);
                return { success: true, method: 'hcaptcha.callback' };
              }
            }
            
            // 方法C: 在所有 iframe 中查找回调
            const frames = document.querySelectorAll('iframe');
            for (const frame of frames) {
              try {
                if (frame.contentWindow && frame.contentWindow.hcaptcha) {
                  if (frame.contentWindow.hcaptcha.setResponse) {
                    frame.contentWindow.hcaptcha.setResponse(token);
                  }
                  if (frame.contentWindow.hcaptcha.callback) {
                    frame.contentWindow.hcaptcha.callback(token);
                    return { success: true, method: 'iframe-hcaptcha.callback' };
                  }
                }
              } catch (e) {
                // 跨域iframe无法访问，跳过
              }
            }
            
            // 触发 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, captchaInfo.callback);
        
        if (!injected.success) {
          throw new Error(`Token 注入失败: ${injected.error}`);
        }
        
        logger.success(this.siteName, `  → ✓ Token 注入成功 (方式: ${injected.method})`);
        if (injected.callback) {
          logger.info(this.siteName, `  → ✓ 已执行回调函数: ${injected.callback}`);
        } else if (injected.callbackExecuted) {
          logger.info(this.siteName, '  → ✓ 已执行 hCaptcha 回调');
        } else {
          logger.info(this.siteName, '  → Token 已注入，准备点击 checkbox');
        }
        
        // 等待更长时间，让 hCaptcha 完全响应（可能降级为图片）
        logger.info(this.siteName, '  → 等待 hCaptcha 响应（5秒）...');
        await this.human.randomDelay(5000, 6000);
        
        // 检测是否有图片挑战出现
        logger.info(this.siteName, '  → 检测验证码状态...');
        const captchaStatus = await this.page.evaluate(() => {
          // 检查所有 iframe
          const iframes = document.querySelectorAll('iframe');
          let hasImageChallenge = false;
          let challengeText = '';
          
          for (const iframe of iframes) {
            try {
              // 检查 iframe 的 src 是否包含 hcaptcha
              if (iframe.src && iframe.src.includes('hcaptcha')) {
                // 尝试访问 iframe 内容（跨域可能失败）
                try {
                  const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                  if (iframeDoc) {
                    const bodyText = iframeDoc.body ? iframeDoc.body.innerText : '';
                    if (bodyText.includes('点击') || bodyText.includes('选择') || bodyText.includes('Select')) {
                      hasImageChallenge = true;
                      challengeText = bodyText.substring(0, 50);
                      break;
                    }
                  }
                } catch (e) {
                  // 跨域 iframe，无法访问内容
                }
                
                // 即使无法访问内容，如果 iframe 存在且可见，也认为可能有挑战
                const rect = iframe.getBoundingClientRect();
                if (rect.width > 300 && rect.height > 300) {
                  hasImageChallenge = true;
                  break;
                }
              }
            } catch (e) {
              // 忽略错误
            }
          }
          
          // 检查主页面的 response
          const response = document.querySelector('[name="h-captcha-response"]') || 
                          document.querySelector('[name="g-recaptcha-response"]');
          const hasResponse = response && response.value && response.value.length > 20;
          
          return {
            hasImageChallenge,
            hasResponse,
            challengeText,
            iframeCount: iframes.length
          };
        });
        
        logger.info(this.siteName, `  → 检测结果: iframe数=${captchaStatus.iframeCount}, 图片挑战=${captchaStatus.hasImageChallenge}, token已填充=${captchaStatus.hasResponse}`);
        
        if (captchaStatus.hasImageChallenge) {
          logger.warn(this.siteName, '  → ⚠️  检测到图片挑战，Token 可能被拒绝！');
          if (captchaStatus.challengeText) {
            logger.info(this.siteName, `  → 挑战内容: ${captchaStatus.challengeText}`);
          }
        }
        
        // 尝试自动点击 checkbox（如果存在）
        logger.info(this.siteName, '  → 尝试自动点击 checkbox...');
        try {
          // 方法1: 通过 iframe.contentFrame() 直接在 iframe 内点击（最正确的方式）
          const frames = this.page.frames();
          let clicked = false;
          
          logger.info(this.siteName, `  → 检测到 ${frames.length} 个 frame`);
          
          for (const frame of frames) {
            try {
              const frameUrl = frame.url();
              
              // 查找 hCaptcha checkbox 的 iframe（通常包含 checkbox 或 anchor）
              if (frameUrl.includes('hcaptcha') && (frameUrl.includes('checkbox') || frameUrl.includes('anchor'))) {
                logger.info(this.siteName, `  → 找到 hCaptcha checkbox frame: ${frameUrl.substring(0, 80)}...`);
                
                // 在 iframe 内查找 checkbox 并点击
                const checkboxClicked = await frame.evaluate(() => {
                  // 查找多种可能的 checkbox 元素
                  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' };
                  }
                  
                  // 如果找不到 checkbox，尝试点击任何可点击的元素
                  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) {
                  logger.success(this.siteName, `  → ✓ 已在 iframe 内点击 checkbox (${checkboxClicked.type})`);
                  clicked = true;
                  break;
                }
              }
            } catch (e) {
              // 跨域 iframe 或其他错误，继续尝试下一个
              logger.debug(this.siteName, `  → Frame 访问失败: ${e.message}`);
            }
          }
          
          // 方法2: 如果方法1失败，使用坐标点击
          if (!clicked) {
            logger.info(this.siteName, '  → 尝试通过坐标点击...');
            
            const clickResult = await this.page.evaluate(() => {
              const iframes = document.querySelectorAll('iframe');
              
              for (const iframe of iframes) {
                try {
                  if (iframe.src && iframe.src.includes('hcaptcha')) {
                    const rect = iframe.getBoundingClientRect();
                    // 小的 iframe 是 checkbox（宽高 50-150px）
                    if (rect.width > 50 && rect.width < 150 && rect.height > 50 && rect.height < 150) {
                      return {
                        found: true,
                        x: Math.round(rect.left + rect.width / 2),
                        y: Math.round(rect.top + rect.height / 2),
                        width: Math.round(rect.width),
                        height: Math.round(rect.height)
                      };
                    }
                  }
                } catch (e) {
                  // 忽略
                }
              }
              return { found: false };
            });
            
            if (clickResult.found) {
              logger.info(this.siteName, `  → 找到 checkbox iframe: 位置(${clickResult.x}, ${clickResult.y}), 尺寸${clickResult.width}x${clickResult.height}`);
              await this.page.mouse.click(clickResult.x, clickResult.y);
              logger.success(this.siteName, `  → ✓ 已点击 checkbox 坐标`);
              clicked = true;
            }
          }
          
          if (clicked) {
            // 等待点击生效
            await this.human.randomDelay(2000, 3000);
            
            // 验证点击是否生效
            const tokenFilled = await this.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 (tokenFilled) {
              logger.success(this.siteName, '  → ✓ Token 已自动填充，验证成功！');
            } else {
              logger.info(this.siteName, '  → Token 尚未填充，继续等待验证...');
            }
          } else {
            logger.info(this.siteName, '  → 未找到可点击的 checkbox');
          }
        } catch (e) {
          logger.warn(this.siteName, `  → 点击 checkbox 失败: ${e.message}`);
        }
        
        await this.human.randomDelay(1000, 2000);
        
        // 等待验证完成（如果回调成功，应该很快；如果降级到图片，需要手动）
        logger.info(this.siteName, '  → 等待验证完成...');
        const startTime = Date.now();
        let dialogClosed = false;
        let hasImageChallenge = captchaStatus.hasImageChallenge;  // 使用前面检测的结果
        const maxWaitTime = 120000; // 图片挑战需要更长时间，最多120秒
        
        if (hasImageChallenge) {
          logger.warn(this.siteName, '  → ⚠️  需要手动完成图片验证（最多等待120秒）...');
        }
        
        while (Date.now() - startTime < maxWaitTime) {
          // 优先检查页面是否跳转（支付成功）
          const currentUrl = this.page.url();
          if (!currentUrl.includes('stripe.com') && !currentUrl.includes('checkout.stripe.com')) {
            dialogClosed = true;
            const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
            logger.success(this.siteName, `  → ✓ 验证完成，页面已跳转（耗时${elapsed}秒）`);
            break;
          }
          
          const status = await this.page.evaluate(() => {
            // 检查 token 是否已填充（主要判断依据）
            const response = document.querySelector('[name="h-captcha-response"]') || 
                           document.querySelector('[name="g-recaptcha-response"]');
            const hasResponse = response && response.value && response.value.length > 20;
            
            // 检查 iframe 中的图片挑战（必须是可见的）
            let hasImageChallenge = false;
            const iframes = document.querySelectorAll('iframe[src*="hcaptcha"]');
            for (const iframe of iframes) {
              const rect = iframe.getBoundingClientRect();
              const style = window.getComputedStyle(iframe);
              const isVisible = style.display !== 'none' && 
                              style.visibility !== 'hidden' && 
                              style.opacity !== '0' &&
                              rect.width > 300 && rect.height > 300;
              
              if (isVisible) {
                hasImageChallenge = true;
                break;
              }
            }
            
            return {
              verified: hasResponse,
              hasImageChallenge: hasImageChallenge,
              iframeCount: iframes.length
            };
          });
          
          // 第一次检测到图片挑战（之前没检测到）
          if (status.hasImageChallenge && !hasImageChallenge) {
            hasImageChallenge = true;
            logger.warn(this.siteName, '  → ⚠️  检测到图片挑战！');
            
            // 尝试使用 2captcha 自动解决图片挑战
            if (this.twoCaptchaSolver) {
              try {
                logger.info(this.siteName, '  → 尝试使用 2Captcha 自动解决图片挑战...');
                
                // 1. 获取挑战信息
                const challengeInfo = await this.page.evaluate(() => {
                  // 查找挑战 iframe
                  const iframes = document.querySelectorAll('iframe[src*="hcaptcha"]');
                  for (const iframe of iframes) {
                    const rect = iframe.getBoundingClientRect();
                    if (rect.width > 300 && rect.height > 300) {
                      // 尝试获取任务文本（可能在主页面或 iframe 外层）
                      let taskText = '';
                      const parentDiv = iframe.closest('div');
                      if (parentDiv) {
                        const textElements = parentDiv.querySelectorAll('h2, h3, div, span, label');
                        for (const el of textElements) {
                          const text = el.textContent?.trim();
                          if (text && (text.includes('点击') || text.includes('选择') || text.includes('Select'))) {
                            taskText = text;
                            break;
                          }
                        }
                      }
                      
                      return {
                        found: true,
                        taskText: taskText,
                        iframeSrc: iframe.src,
                        rect: {
                          x: rect.x,
                          y: rect.y,
                          width: rect.width,
                          height: rect.height
                        }
                      };
                    }
                  }
                  return { found: false };
                });
                
                if (challengeInfo.found) {
                  logger.info(this.siteName, `  → 挑战任务: ${challengeInfo.taskText || '未检测到任务文本'}`);
                  
                  // 2. 截取挑战图片
                  const challengeFrame = this.page.frames().find(f => f.url().includes('hcaptcha') && f.url().includes('challenge'));
                  if (challengeFrame) {
                    // 等待图片加载
                    await this.human.randomDelay(2000, 3000);
                    
                    // 截取挑战区域的图片
                    const screenshot = await this.page.screenshot({
                      clip: {
                        x: challengeInfo.rect.x,
                        y: challengeInfo.rect.y,
                        width: challengeInfo.rect.width,
                        height: challengeInfo.rect.height
                      },
                      encoding: 'base64'
                    });
                    
                    logger.info(this.siteName, '  → 正在发送到 2Captcha 识别...');
                    
                    // 3. 使用 2captcha coordinates API
                    const result = await this.twoCaptchaSolver.coordinates({
                      body: screenshot,
                      textinstructions: challengeInfo.taskText || '点击正确的图片'
                    });
                    
                    logger.success(this.siteName, `  → ✓ 2Captcha 识别成功！耗时: ${result.cost}秒`);
                    
                    // 4. 点击识别出的坐标
                    const coords = result.data.split(',').map(coord => {
                      const [key, value] = coord.split(':');
                      return { [key]: parseInt(value) };
                    }).reduce((acc, curr) => ({ ...acc, ...curr }), {});
                    
                    if (coords.x && coords.y) {
                      // 转换为屏幕坐标
                      const clickX = challengeInfo.rect.x + coords.x;
                      const clickY = challengeInfo.rect.y + coords.y;
                      
                      logger.info(this.siteName, `  → 点击坐标: (${clickX}, ${clickY})`);
                      await this.page.mouse.click(clickX, clickY);
                      logger.success(this.siteName, '  → ✓ 已点击识别结果');
                      
                      // 等待并点击提交按钮（通常是"验证"或"检查"按钮）
                      await this.human.randomDelay(1000, 1500);
                      
                      // 查找并点击提交按钮
                      const submitClicked = await challengeFrame.evaluate(() => {
                        const buttons = document.querySelectorAll('button, [role="button"]');
                        for (const btn of buttons) {
                          const text = btn.textContent?.trim();
                          if (text && (text.includes('验证') || text.includes('检查') || text.includes('Verify') || text.includes('Submit'))) {
                            btn.click();
                            return true;
                          }
                        }
                        return false;
                      });
                      
                      if (submitClicked) {
                        logger.success(this.siteName, '  → ✓ 已提交验证');
                      }
                      
                      // 等待验证结果
                      await this.human.randomDelay(2000, 3000);
                    }
                  } else {
                    logger.warn(this.siteName, '  → 未找到挑战 iframe');
                    logger.warn(this.siteName, '  → 请手动完成图片验证...');
                  }
                } else {
                  logger.warn(this.siteName, '  → 未找到挑战信息');
                  logger.warn(this.siteName, '  → 请手动完成图片验证...');
                }
              } catch (error) {
                logger.error(this.siteName, `  → 2Captcha 自动解决失败: ${error.message}`);
                logger.warn(this.siteName, '  → 请手动完成图片验证...');
              }
            } else {
              logger.warn(this.siteName, '  → 请手动完成图片验证...');
            }
          }
          
          // 验证完成的条件：token 已填充（不管 iframe 是否还存在）
          if (status.verified) {
            dialogClosed = true;
            const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
            logger.success(this.siteName, `  → ✓ 验证完成（耗时${elapsed}秒）`);
            if (status.hasImageChallenge) {
              logger.info(this.siteName, '  → 图片挑战 iframe 仍存在，但 token 已填充，视为完成');
            }
            break;
          }
          
          // 每10秒输出一次进度（仅在有图片挑战时）
          if (hasImageChallenge) {
            const elapsed = Date.now() - startTime;
            if (elapsed > 0 && elapsed % 10000 === 0) {
              logger.info(this.siteName, `  → 等待手动验证... (${(elapsed/1000).toFixed(0)}秒)`);
            }
          }
          
          // 动态调整检查间隔
          const interval = hasImageChallenge ? 2000 : 1000;
          await new Promise(resolve => setTimeout(resolve, interval));
        }
        
        if (!dialogClosed) {
          logger.error(this.siteName, '  → ✗ 验证超时（120秒）！');
          logger.warn(this.siteName, '  → 验证码可能还在页面上，需要手动完成或重新提交');
          return false;  // 返回 false，不要继续
        }
        
        await this.human.randomDelay(1000, 2000);
        return true;
        
      } catch (error) {
        logger.error(this.siteName, `  → ✗ YesCaptcha 自动识别失败: ${error.message}`);
        logger.warn(this.siteName, '  → 将回退到手动模式');
      }
    } else {
      logger.warn(this.siteName, '  → 未配置 YesCaptcha API Key');
    }
    
    // 手动等待模式
    logger.warn(this.siteName, '  → 请手动完成验证码（等待120秒）...');
    const startWait = Date.now();
    
    while (Date.now() - startWait < 120000) {
      const captchaSolved = await this.page.evaluate(() => {
        const response = document.querySelector('[name="h-captcha-response"]') || 
                        document.querySelector('[name="g-recaptcha-response"]');
        return response && response.value && response.value.length > 0;
      });
      
      if (captchaSolved) {
        logger.success(this.siteName, '  → ✓ 验证码已完成');
        return true;
      }
      
      // 每10秒输出一次进度
      const elapsed = Date.now() - startWait;
      if (elapsed > 0 && elapsed % 10000 === 0) {
        logger.info(this.siteName, `  → 等待验证码... (${(elapsed/1000).toFixed(0)}秒)`);
      }
      
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
    
    logger.error(this.siteName, '  → ✗ 验证码超时（120秒）');
    return false;
  }
  
  /**
   * 检查银行卡是否被拒绝
   */
  async checkCardRejected() {
    return await this.page.evaluate(() => {
      const errorContainers = [
        '.FieldError-container',
        '[class*="Error"]',
        '[class*="error"]',
        '.error-message'
      ];
      for (const selector of errorContainers) {
        const elements = document.querySelectorAll(selector);
        for (const el of elements) {
          const text = el.textContent || '';
          // 检查卡被拒绝或卡号无效
          if (text.includes('银行卡') && text.includes('拒绝') ||
              text.includes('您的银行卡被拒绝了') ||
              text.includes('card was declined') ||
              text.includes('被拒绝') ||
              text.includes('declined') ||
              text.includes('卡号无效') ||
              text.includes('您的卡号无效') ||
              text.includes('invalid card') ||
              text.includes('card number is invalid') ||
              text.includes('无效')) {
            return true;
          }
        }
      }
      return false;
    });
  }
  
  /**
   * 等待支付成功
   */
  async waitForPaymentSuccess() {
    const paymentStartTime = Date.now();
    logger.info(this.siteName, '  → 等待支付处理...');
    
    while (true) {
      const currentUrl = this.page.url();
      if (!currentUrl.includes('stripe.com') && !currentUrl.includes('checkout.stripe.com')) {
        const totalTime = ((Date.now() - paymentStartTime) / 1000).toFixed(1);
        this.registrationTime = new Date();
        logger.success(this.siteName, `  → ✓ 支付成功！(耗时: ${totalTime}秒)`);
        logger.info(this.siteName, `  → 当前页面: ${currentUrl}`);
        return true;
      }
      const elapsed = Date.now() - paymentStartTime;
      if (elapsed > 0 && elapsed % 5000 === 0) {
        logger.info(this.siteName, `  → 支付处理中... (${(elapsed/1000).toFixed(0)}秒)`);
      }
      await new Promise(resolve => setTimeout(resolve, 500));
    }
  }
  
  /**
   * 提交支付（递归重试，轮询检测）
   */
  async submitPayment(retryCount = 0, maxRetries = 5) {
    if (retryCount >= maxRetries) {
      throw new Error(`银行卡被拒绝，已重试 ${maxRetries} 次`);
    }
    
    if (retryCount > 0) {
      logger.info(this.siteName, `  → 第 ${retryCount + 1} 次尝试提交...`);
    }
    
    // 点击订阅按钮（增强版）
    logger.info(this.siteName, '  → 查找订阅按钮...');
    
    // 等待按钮可点击
    await this.human.randomDelay(500, 1000);
    
    const clicked = await this.page.evaluate(() => {
      // 查找订阅按钮的多种方式
      let button = null;
      
      // 方式1: 精确选择器
      button = document.querySelector('button[type="submit"][data-testid="hosted-payment-submit-button"]');
      
      // 方式2: 通过文本内容查找
      if (!button) {
        const buttons = document.querySelectorAll('button[type="submit"]');
        for (const btn of buttons) {
          const text = (btn.innerText || btn.textContent || '').toLowerCase();
          if (text.includes('订阅') || text.includes('subscribe') || text.includes('start')) {
            button = btn;
            break;
          }
        }
      }
      
      // 方式3: 任意 submit 按钮
      if (!button) {
        button = document.querySelector('button[type="submit"]');
      }
      
      if (!button) {
        return { success: false, reason: 'not-found' };
      }
      
      // 检查按钮状态
      const rect = button.getBoundingClientRect();
      const isVisible = rect.width > 0 && rect.height > 0 && 
                       rect.top >= 0 && rect.top <= window.innerHeight;
      const isDisabled = button.disabled || button.getAttribute('aria-disabled') === 'true';
      const buttonText = button.innerText || button.textContent || '';
      
      if (isDisabled) {
        return { success: false, reason: 'disabled', text: buttonText };
      }
      
      if (!isVisible) {
        // 滚动到按钮位置
        button.scrollIntoView({ behavior: 'smooth', block: 'center' });
        // 等待滚动完成
        return { success: false, reason: 'scrolling', text: buttonText, needScroll: true };
      }
      
      // 点击按钮
      try {
        button.click();
        return { 
          success: true, 
          text: buttonText,
          coords: { x: Math.round(rect.left + rect.width/2), y: Math.round(rect.top + rect.height/2) }
        };
      } catch (e) {
        return { success: false, reason: 'click-failed', error: e.message };
      }
    });
    
    if (!clicked.success) {
      if (clicked.needScroll) {
        logger.info(this.siteName, `  → 按钮不在可视区域，已滚动，重试点击...`);
        await this.human.randomDelay(500, 1000);
        // 重试一次
        const retryClicked = await this.page.evaluate(() => {
          const button = document.querySelector('button[type="submit"]');
          if (button) {
            button.click();
            return { success: true, text: button.innerText };
          }
          return { success: false };
        });
        if (!retryClicked.success) {
          logger.warn(this.siteName, `  → 订阅按钮点击失败: ${clicked.reason}`);
          return false;
        }
        logger.success(this.siteName, `  → ✓ 已点击订阅按钮: "${retryClicked.text}"`);
      } else {
        logger.warn(this.siteName, `  → 订阅按钮点击失败: ${clicked.reason}`);
        return false;
      }
    } else {
      logger.success(this.siteName, `  → ✓ 已点击订阅按钮: "${clicked.text}"`);
    }
    
    // 等待一下，验证按钮状态变化
    await this.human.randomDelay(1000, 1500);
    
    // 验证点击是否生效（按钮文字应该变为"正在处理"或按钮被禁用）
    const verified = await this.page.evaluate(() => {
      const button = document.querySelector('button[type="submit"]');
      if (!button) return { changed: false };
      
      const text = button.innerText || button.textContent || '';
      const isDisabled = button.disabled || button.getAttribute('aria-disabled') === 'true';
      const isProcessing = text.includes('处理') || text.includes('Processing') || 
                          text.includes('Loading') || text.includes('Submitting');
      
      return {
        changed: isDisabled || isProcessing,
        text: text,
        disabled: isDisabled
      };
    });
    
    if (verified.changed) {
      logger.success(this.siteName, `  → ✓ 订阅按钮状态已变化: "${verified.text}"`);
    } else {
      logger.warn(this.siteName, `  → ⚠️  按钮状态未变化，可能点击未生效，当前文字: "${verified.text}"`);
    }
    
    // 等待 Stripe 开始处理
    await this.human.randomDelay(1000, 2000);
    
    // 检查是否有验证码（每次提交都检查）
    // 等待可能的验证码弹窗/iframe 加载（最多等5秒）
    let captchaDetected = false;
    const checkStartTime = Date.now();
    const maxCheckTime = 5000; // 最多检查5秒
    let captchaCheckCount = 0;
    
    logger.info(this.siteName, `  → 检查验证码状态（第 ${retryCount + 1} 次提交）...`);
    
    while (Date.now() - checkStartTime < maxCheckTime && !captchaDetected) {
      captchaCheckCount++;
      
      const captchaCheck = await this.page.evaluate(() => {
        // 检查多种可能的验证码 iframe 和对话框
        const stripeHCaptchaFrame = document.querySelector('iframe[src*="hcaptcha-inner"]');
        const hcaptchaFrame = document.querySelector('iframe[src*="hcaptcha.com"]');
        const hcaptchaDiv = document.querySelector('.h-captcha');
        
        // 检查是否有"还需一步即可完成"的对话框
        const modalTexts = Array.from(document.querySelectorAll('*')).map(el => el.textContent);
        const hasCaptchaModal = modalTexts.some(text => 
          text && (text.includes('还需一步') || text.includes('我是真实访问者') || text.includes('hCaptcha'))
        );
        
        return {
          hasStripeFrame: !!stripeHCaptchaFrame,
          hasHCaptchaFrame: !!hcaptchaFrame,
          hasDiv: !!hcaptchaDiv,
          hasModal: hasCaptchaModal,
          stripeFrameUrl: stripeHCaptchaFrame ? stripeHCaptchaFrame.src.substring(0, 100) : null
        };
      });
      
      // 只要检测到任一验证码元素就退出循环
      if (captchaCheck.hasStripeFrame || captchaCheck.hasHCaptchaFrame || 
          captchaCheck.hasDiv || captchaCheck.hasModal) {
        captchaDetected = true;
        logger.info(this.siteName, `  → 检测到验证码（第${captchaCheckCount}次检查，${((Date.now() - checkStartTime) / 1000).toFixed(1)}秒）`);
        if (captchaCheck.hasModal) {
          logger.info(this.siteName, `  → 检测到验证码对话框`);
        }
        if (captchaCheck.stripeFrameUrl) {
          logger.info(this.siteName, `  → Stripe hCaptcha URL: ${captchaCheck.stripeFrameUrl}...`);
        }
      } else {
        // 每500ms检查一次
        await new Promise(resolve => setTimeout(resolve, 500));
      }
    }
    
    if (captchaDetected) {
      logger.info(this.siteName, '  → 检测到验证码，使用 YesCaptcha API 处理...');
      // 使用 YesCaptcha API 处理
      const captchaSolved = await this.handleHCaptcha();
      if (!captchaSolved) {
        logger.error(this.siteName, '  → ✗ 验证码自动处理失败！');
        logger.warn(this.siteName, '  → 继续检测支付结果（可能用户已手动完成，或卡被拒绝需要重试）');
        // ✅ 不要直接返回 false，继续执行，检测支付结果
      } else {
        logger.success(this.siteName, '  → ✓ 验证码处理成功');
      }
      await this.human.randomDelay(1000, 2000);
    } else {
      logger.info(this.siteName, `  → ✓ 无验证码（检查${captchaCheckCount}次，耗时${((Date.now() - checkStartTime) / 1000).toFixed(1)}秒）`);
    }
    
    // 开始轮询检测：同时等待成功或失败
    logger.info(this.siteName, '  → 轮询检测支付结果...');
    const startTime = Date.now();
    const maxWait = 30000; // 最多等待30秒
    let checkCount = 0;
    
    while (Date.now() - startTime < maxWait) {
      checkCount++;
      
      // 1. 优先检查是否有错误（卡被拒绝）
      const cardRejected = await this.checkCardRejected();
      if (cardRejected) {
        logger.warn(this.siteName, `  → ⚠️ 银行卡被拒绝！(第 ${retryCount + 1}/${maxRetries} 次，检测了 ${checkCount} 次)`);
        
        // 等待错误信息完全显示（1-2秒）
        await this.human.randomDelay(1000, 2000);
        
        // 生成新卡
        logger.info(this.siteName, '  → 生成新的银行卡信息...');
        const cardGen = new CardGenerator();
        const newCard = cardGen.generate('unionpay');
        logger.info(this.siteName, `  → 新卡号: ${newCard.number}`);
        
        this.cardInfo = {
          number: newCard.number,
          month: newCard.month,
          year: newCard.year,
          cvv: newCard.cvv,
          country: 'MO'
        };
        
        // 检查页面状态，确保表单仍然可用
        try {
          await this.page.waitForFunction(
            () => {
              const cardNumber = document.querySelector('#cardNumber');
              const cardExpiry = document.querySelector('#cardExpiry');
              const cardCvc = document.querySelector('#cardCvc');
              return cardNumber && cardExpiry && cardCvc;
            },
            { timeout: 5000 }
          );
        } catch (e) {
          logger.warn(this.siteName, `  → 表单可能已刷新，等待恢复...`);
          await this.human.randomDelay(2000, 3000);
        }
        
        // 模拟人工思考（1-2秒）
        await this.human.randomDelay(1000, 2000);
        
        // 重新填写卡信息
        await this.fillCardForm(newCard, true);
        logger.success(this.siteName, '  → ✓ 已更新银行卡信息');
        
        // 填写后等待页面响应（2-3秒）
        await this.human.randomDelay(2000, 3000);
        
        // 递归重试
        return await this.submitPayment(retryCount + 1, maxRetries);
      }
      
      // 2. 检查是否支付成功（跳转离开 Stripe）
      const currentUrl = this.page.url();
      if (!currentUrl.includes('stripe.com') && !currentUrl.includes('checkout.stripe.com')) {
        const totalTime = ((Date.now() - startTime) / 1000).toFixed(1);
        this.registrationTime = new Date();
        logger.success(this.siteName, `  → ✓ 支付成功！(耗时: ${totalTime}秒，检测了 ${checkCount} 次)`);
        logger.info(this.siteName, `  → 当前页面: ${currentUrl}`);
        return true;
      }
      
      // 3. 每5秒输出一次进度
      const elapsed = Date.now() - startTime;
      if (elapsed > 0 && elapsed % 5000 === 0) {
        logger.info(this.siteName, `  → 支付处理中... (${(elapsed/1000).toFixed(0)}秒，已检测 ${checkCount} 次)`);
      }
      
      // 4. 等待500ms后继续检测
      await new Promise(resolve => setTimeout(resolve, 500));
    }
    
    // 超时：视为可能失败，生成新卡重试
    logger.warn(this.siteName, `  → ⚠️ 支付超时（${maxWait/1000}秒），共检测 ${checkCount} 次`);
    logger.info(this.siteName, `  → 将生成新卡重试 (第 ${retryCount + 1}/${maxRetries} 次)`);
    
    // 等待页面稳定（1-2秒）
    await this.human.randomDelay(1000, 2000);
    
    // 生成新卡
    const cardGen = new CardGenerator();
    const newCard = cardGen.generate('unionpay');
    logger.info(this.siteName, `  → 新卡号: ${newCard.number}`);
    
    this.cardInfo = {
      number: newCard.number,
      month: newCard.month,
      year: newCard.year,
      cvv: newCard.cvv,
      country: 'MO'
    };
    
    // 检查页面状态
    try {
      await this.page.waitForFunction(
        () => {
          const cardNumber = document.querySelector('#cardNumber');
          const cardExpiry = document.querySelector('#cardExpiry');
          const cardCvc = document.querySelector('#cardCvc');
          return cardNumber && cardExpiry && cardCvc;
        },
        { timeout: 5000 }
      );
    } catch (e) {
      logger.warn(this.siteName, `  → 表单可能已刷新，等待恢复...`);
      await this.human.randomDelay(2000, 3000);
    }
    
    // 模拟人工思考（1-2秒）
    await this.human.randomDelay(1000, 2000);
    
    // 重新填写卡信息
    await this.fillCardForm(newCard, true);
    logger.success(this.siteName, '  → ✓ 已更新银行卡信息');
    
    // 填写后等待（2-3秒）
    await this.human.randomDelay(2000, 3000);
    
    // 递归重试
    return await this.submitPayment(retryCount + 1, maxRetries);
  }
  
  /**
   * 步骤6: 填写支付信息
   */
  async step6_fillPayment() {
    logger.info(this.siteName, `[步骤 6/${this.getTotalSteps()}] 填写支付信息`);
    
    try {
      await this.human.readPage(3, 5);
      
      // 生成银行卡
      logger.info(this.siteName, '  → 生成银联卡信息...');
      const cardGen = new CardGenerator();
      const card = cardGen.generate('unionpay');
      logger.info(this.siteName, `  → 卡号: ${card.number}`);
      logger.info(this.siteName, `  → 有效期: ${card.month}/${card.year}`);
      logger.info(this.siteName, `  → CVV: ${card.cvv}`);
      
      this.cardInfo = {
        number: card.number,
        month: card.month,
        year: card.year,
        cvv: card.cvv,
        country: 'MO'
      };
      
      // 填写卡表单（带重试）
      let fillSuccess = false;
      const maxFillRetries = 2;
      
      for (let retry = 0; retry < maxFillRetries; retry++) {
        if (retry > 0) {
          logger.warn(this.siteName, `  → 第 ${retry + 1} 次尝试填写表单...`);
          await this.human.randomDelay(2000, 3000);
          
          // 刷新页面重试
          try {
            await this.page.reload({ waitUntil: 'networkidle0', timeout: 15000 });
            await this.human.randomDelay(3000, 5000);
          } catch (e) {
            logger.warn(this.siteName, `  → 刷新页面失败: ${e.message}`);
          }
        }
        
        fillSuccess = await this.fillCardForm(card);
        if (fillSuccess) {
          break;
        }
        
        // 截图调试
        try {
          const screenshot = `/tmp/windsurf-fill-failed-retry${retry}-${Date.now()}.png`;
          await this.page.screenshot({ path: screenshot });
          logger.info(this.siteName, `  → 调试截图: ${screenshot}`);
        } catch (e) {}
      }
      
      if (!fillSuccess) {
        logger.error(this.siteName, `✗ 填写支付表单失败（已重试 ${maxFillRetries} 次），跳过此账号`);
        throw new Error('填写支付表单失败');
      }
      
      await this.human.randomDelay(2000, 3000);
      
      // 提交支付（递归重试）
      const submitSuccess = await this.submitPayment();
      if (!submitSuccess) {
        logger.error(this.siteName, '✗ 提交支付失败，跳过此账号');
        throw new Error('提交支付失败');
      }
      
      this.currentStep = 6;
      logger.success(this.siteName, `步骤 6 完成`);
      
    } catch (error) {
      logger.error(this.siteName, `填写支付信息失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 步骤7: 获取订阅信息
   */
  async step7_getSubscriptionInfo() {
    logger.info(this.siteName, `[步骤 7/${this.getTotalSteps()}] 获取订阅信息`);
    
    try {
      // 0. 先关闭多余的窗口/标签页
      logger.info(this.siteName, '  → 检查并关闭多余窗口...');
      try {
        const pages = await this.browser.pages();
        logger.info(this.siteName, `  → 当前共有 ${pages.length} 个页面`);
        
        if (pages.length > 1) {
          // 保留一个 windsurf.com 的页面，关闭其他
          let validPage = null;
          const pagesToClose = [];
          
          for (const page of pages) {
            try {
              const url = page.url();
              if (url.includes('windsurf.com') && !validPage) {
                validPage = page;
                logger.info(this.siteName, `  → ✓ 保留: ${url}`);
              } else {
                pagesToClose.push(page);
                logger.info(this.siteName, `  → ✗ 关闭: ${url}`);
              }
            } catch (e) {
              pagesToClose.push(page);
            }
          }
          
          // 如果没找到 windsurf 页面，保留第一个
          if (!validPage && pages.length > 0) {
            validPage = pages[0];
            pagesToClose.shift();
          }
          
          // 关闭多余页面
          for (const page of pagesToClose) {
            try {
              await page.close();
            } catch (e) {
              // 忽略
            }
          }
          
          this.page = validPage;
          logger.success(this.siteName, `  → ✓ 已关闭 ${pagesToClose.length} 个多余页面`);
        }
      } catch (e) {
        logger.warn(this.siteName, `  → 关闭窗口失败: ${e.message}`);
      }
      
      await this.human.randomDelay(1000, 2000);
      
      // 1. 持续按ESC关闭弹窗（循环5次，确保关闭）
      logger.info(this.siteName, '  → 关闭可能存在的对话框...');
      for (let i = 0; i < 5; i++) {
        try {
          await this.page.keyboard.press('Escape');
          await new Promise(resolve => setTimeout(resolve, 300));
        } catch (e) {
          // 忽略
        }
      }
      logger.success(this.siteName, '  → ✓ 已按5次ESC键');
      
      await this.human.randomDelay(500, 1000);
      
      // 2. 跳转到订阅使用页面
      logger.info(this.siteName, '  → 跳转到订阅使用页面...');
      const currentUrl = this.page.url();
      logger.info(this.siteName, `  → 当前页面: ${currentUrl}`);
      
      await this.page.goto('https://windsurf.com/subscription/usage', { 
        waitUntil: 'networkidle2',
        timeout: 30000 
      });
      
      // 等待页面加载
      await this.human.randomDelay(3000, 5000);
      
      // 2. 获取配额信息
      logger.info(this.siteName, '  → 获取配额信息...');
      const quotaInfo = await this.page.evaluate(() => {
        // 查找包含配额的 p 标签
        const quotaElement = document.querySelector('p.caption1.font-medium.text-sk-black\\/80');
        if (!quotaElement) return null;
        
        const spans = quotaElement.querySelectorAll('span.caption3 span');
        if (spans.length >= 2) {
          const used = spans[0].textContent.trim();
          const total = spans[1].textContent.trim().replace('/', '').trim();
          return { used, total };
        }
        return null;
      });
      
      if (quotaInfo) {
        logger.success(this.siteName, `  → ✓ 配额: ${quotaInfo.used} / ${quotaInfo.total} used`);
      } else {
        logger.warn(this.siteName, '  → ⚠️ 未找到配额信息');
      }
      
      // 3. 获取下次账单日期信息
      logger.info(this.siteName, '  → 获取账单周期信息...');
      const billingInfo = await this.page.evaluate(() => {
        // 查找包含 "Next billing cycle" 的 p 标签
        const billingElement = Array.from(document.querySelectorAll('p.caption1'))
          .find(p => p.textContent.includes('Next billing cycle'));
        
        if (!billingElement) return null;
        
        // 提取天数
        const daysMatch = billingElement.textContent.match(/(\d+)\s+days?/);
        const dateMatch = billingElement.textContent.match(/on\s+([A-Za-z]+\s+\d+,\s+\d{4})/);
        
        return {
          days: daysMatch ? daysMatch[1] : null,
          date: dateMatch ? dateMatch[1] : null,
          fullText: billingElement.textContent.trim()
        };
      });
      
      if (billingInfo && billingInfo.days) {
        logger.success(this.siteName, `  → ✓ 下次账单: ${billingInfo.days} 天后 (${billingInfo.date})`);
      } else {
        logger.warn(this.siteName, '  → ⚠️ 未找到账单周期信息');
      }
      
      // 4. 简要打印关键信息
      logger.success(this.siteName, `✓ 配额: ${quotaInfo ? `${quotaInfo.used}/${quotaInfo.total}` : 'N/A'} | 下次账单: ${billingInfo?.days || 'N/A'}天后`);
      
      // 保存订阅信息供后续使用
      this.quotaInfo = quotaInfo;
      this.billingInfo = billingInfo;
      
      this.currentStep = 7;
      logger.success(this.siteName, `步骤 7 完成`);
      
    } catch (error) {
      logger.error(this.siteName, `获取订阅信息失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 步骤8: 保存到数据库
   */
  async step8_saveToDatabase() {
    logger.info(this.siteName, `[步骤 8/${this.getTotalSteps()}] 保存到数据库`);
    
    try {
      // 初始化数据库连接
      logger.info(this.siteName, '  → 连接数据库...');
      await database.initialize();
      
      // 准备账号数据
      const accountData = {
        email: this.accountData.email,
        password: this.accountData.password,
        firstName: this.accountData.firstName,
        lastName: this.accountData.lastName,
        registrationTime: this.registrationTime,
        quotaUsed: this.quotaInfo ? parseFloat(this.quotaInfo.used) : 0,
        quotaTotal: this.quotaInfo ? parseFloat(this.quotaInfo.total) : 0,
        billingDays: this.billingInfo ? parseInt(this.billingInfo.days) : null,
        billingDate: this.billingInfo ? this.billingInfo.date : null,
        paymentCardNumber: this.cardInfo ? this.cardInfo.number : null,
        paymentCountry: this.cardInfo ? this.cardInfo.country : 'MO',
        status: 'active',
        isOnSale: false
      };
      
      // 保存到数据库
      logger.info(this.siteName, '  → 保存账号信息...');
      const accountRepo = database.getRepository('account');
      const accountId = await accountRepo.create(accountData);
      
      logger.success(this.siteName, `  → ✓ 账号信息已保存到数据库 (ID: ${accountId})`);
      logger.info(this.siteName, `  → 邮箱: ${accountData.email}`);
      logger.info(this.siteName, `  → 配额: ${accountData.quotaUsed} / ${accountData.quotaTotal}`);
      logger.info(this.siteName, `  → 卡号: ${accountData.paymentCardNumber}`);
      
      this.currentStep = 8;
      logger.success(this.siteName, `步骤 8 完成`);
      
    } catch (error) {
      logger.error(this.siteName, `保存到数据库失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 步骤9: 清理并关闭浏览器
   */
  async step9_clearAndCloseBrowser() {
    logger.info(this.siteName, `[步骤 9/${this.getTotalSteps()}] 清理并关闭浏览器`);
    
    try {
      await this.browserManager.clearAndClose();
      
      this.currentStep = 9;
      logger.success(this.siteName, `步骤 9 完成`);
      
    } catch (error) {
      logger.error(this.siteName, `清理并关闭浏览器失败: ${error.message}`);
      throw error;
    }
  }

  /**
   * 执行注册流程
   * @param {Object} options - 选项
   * @param {number} options.fromStep - 从第几步开始（默认1）
   * @param {number} options.toStep - 执行到第几步（默认全部）
   */
  async register(options = {}) {
    const fromStep = options.fromStep || 1;
    const toStep = options.toStep || this.getTotalSteps();
    
    try {
      // 1. 生成数据
      this.accountData = this.generateData(options);
      logger.success(this.siteName, '账号数据生成完成');
      logger.info(this.siteName, `First Name: ${this.accountData.firstName}`);
      logger.info(this.siteName, `Last Name: ${this.accountData.lastName}`);
      logger.info(this.siteName, `Email: ${this.accountData.email}`);
      logger.info(this.siteName, `Password: ${this.accountData.password}`);

      // 2. 初始化浏览器
      await this.initBrowser();

      // 3. 执行指定范围的步骤
      logger.info(this.siteName, `\n开始执行步骤 ${fromStep} 到 ${toStep} (共 ${this.getTotalSteps()} 步)\n`);
      
      for (let i = fromStep; i <= toStep && i <= this.getTotalSteps(); i++) {
        const step = this.steps[i - 1];
        
        if (typeof this[step.method] === 'function') {
          try {
            await this[step.method]();
          } catch (error) {
            logger.error(this.siteName, `步骤 ${i} 执行失败: ${error.message}`);
            throw error;
          }
        } else {
          logger.warn(this.siteName, `步骤 ${i} (${step.name}) 未实现`);
          break;
        }
      }

      const stepInfo = this.getCurrentStepInfo();
      logger.success(this.siteName, `\n✅ 所有步骤已完成 (${fromStep} 到 ${this.currentStep})`);

      return {
        success: true,
        account: this.accountData,
        completedSteps: this.currentStep,
        totalSteps: this.getTotalSteps(),
        message: `完成 ${this.currentStep}/${this.getTotalSteps()} 步`
      };

    } catch (error) {
      logger.error(this.siteName, `注册失败: ${error.message}`);
      
      // 截图保存错误状态
      if (this.page) {
        try {
          const screenshotPath = `/tmp/windsurf-error-${Date.now()}.png`;
          await this.page.screenshot({ path: screenshotPath });
          logger.info(this.siteName, `错误截图已保存: ${screenshotPath}`);
        } catch (e) {
          // 忽略截图错误
        }
      }

      // 清理浏览器缓存并关闭
      if (this.page) {
        try {
          logger.info(this.siteName, '  → 清除浏览器缓存...');
          const client = await this.page.target().createCDPSession();
          await client.send('Network.clearBrowserCookies');
          await client.send('Network.clearBrowserCache');
          await client.send('Storage.clearDataForOrigin', {
            origin: '*',
            storageTypes: 'all'
          });
          await this.page.goto('https://windsurf.com', { waitUntil: 'domcontentloaded' });
          await this.page.evaluate(() => {
            try {
              localStorage.clear();
              sessionStorage.clear();
            } catch (e) {}
          });
          await client.detach();
          logger.success(this.siteName, '  → ✓ 浏览器缓存已清除');
        } catch (e) {
          logger.warn(this.siteName, `  → 清除缓存失败: ${e.message}`);
        }
      }

      await this.closeBrowser();
      
      throw error;
    }
  }
}

module.exports = WindsurfRegister;
