const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const WorkflowEngine = require('./workflow-engine');

/**
 * 站点适配器基类 - 所有网站的基类
 */
class SiteAdapter {
  constructor(context, siteName) {
    this.context = context;
    this.siteName = siteName;
    this.useConfig = true;  // 默认使用配置文件
    
    // 快捷访问
    this.page = context.page;
    this.logger = context.logger;
    
    // 加载配置
    if (this.useConfig) {
      this.config = this.loadConfig(siteName);
      this.context.siteName = this.config.site?.name || siteName;
    }
  }
  
  /**
   * 加载站点配置
   * @param {string} siteName - 站点名称
   * @returns {Object}
   */
  loadConfig(siteName) {
    const configPath = path.join(__dirname, '../configs/sites', `${siteName}.yaml`);
    
    if (!fs.existsSync(configPath)) {
      throw new Error(`配置文件不存在: ${configPath}`);
    }
    
    const configContent = fs.readFileSync(configPath, 'utf8');
    return yaml.load(configContent);
  }
  
  /**
   * 生命周期钩子 - 工作流执行前
   */
  async beforeWorkflow() {
    this.log('info', `开始执行 ${this.siteName} 工作流`);
    
    // 清除浏览器状态（Cookie、缓存）
    await this.clearBrowserState();
    
    this.log('debug', '执行 beforeWorkflow 钩子');
    // 子类可以重写
  }
  
  /**
   * 清除浏览器状态（模拟真实用户操作：Ctrl+Shift+Delete）
   */
  async clearBrowserState() {
    this.log('info', '清除浏览器状态...');
    
    try {
      // 模拟真实用户操作：Ctrl+Shift+Delete
      this.log('debug', '模拟 Ctrl+Shift+Delete 打开清除对话框...');
      
      // 按下快捷键打开清除浏览数据对话框
      await this.page.keyboard.down('Control');
      await this.page.keyboard.down('Shift');
      await this.page.keyboard.press('Delete');
      await this.page.keyboard.up('Shift');
      await this.page.keyboard.up('Control');
      
      // 等待对话框出现
      await new Promise(resolve => setTimeout(resolve, 1500));
      
      this.log('debug', '选择清除选项...');
      
      // 按 Tab 键导航并选择所有选项（通用方法）
      // 不同浏览器可能有不同的界面，这里用快捷键方式更通用
      
      // 全选时间范围（通常是第一个下拉框，选择"所有时间"）
      await this.page.keyboard.press('Tab'); // 移到时间范围
      await this.page.keyboard.press('Space'); // 打开下拉
      await new Promise(resolve => setTimeout(resolve, 300));
      await this.page.keyboard.press('End'); // 选择最后一项（通常是"所有时间"）
      await this.page.keyboard.press('Enter'); // 确认
      await new Promise(resolve => setTimeout(resolve, 300));
      
      // 勾选所有清除选项（通过 Tab + Space）
      for (let i = 0; i < 8; i++) {
        await this.page.keyboard.press('Tab');
        await this.page.keyboard.press('Space'); // 勾选
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      
      this.log('debug', '点击清除数据按钮...');
      
      // 找到并点击"清除数据"按钮（通常可以用 Enter 或继续 Tab 到按钮）
      await this.page.keyboard.press('Enter');
      
      // 等待清除完成
      await new Promise(resolve => setTimeout(resolve, 2000));
      
      this.log('info', '✓ 已清除浏览器缓存');
      
    } catch (error) {
      this.log('warn', `⚠ WARNING: 清除浏览器状态失败: ${error.message}`);
      this.log('debug', '尝试备用清理方法...');
      
      // 备用方案：直接删除 Cookie（不使用 CDP）
      try {
        const cookies = await this.page.cookies();
        if (cookies.length > 0) {
          await this.page.deleteCookie(...cookies);
          this.log('info', '✓ 已使用备用方法清除 Cookie');
        }
      } catch (e) {
        this.log('warn', `备用清理也失败: ${e.message}`);
      }
    }
  }
  
  /**
   * 生命周期钩子 - 工作流执行后
   */
  async afterWorkflow() {
    this.log('debug', '执行 afterWorkflow 钩子');
    // 子类可以重写
  }
  
  /**
   * 生命周期钩子 - 错误处理
   * @param {Error} error - 错误对象
   */
  async onError(error) {
    this.log('error', `错误: ${error.message}`);
    // 子类可以重写
  }
  
  /**
   * 执行重试策略（框架通用方法）
   */
  async executeRetryStrategy(strategy, retryCount, options = {}) {
    switch (strategy) {
      case 'refresh':
        this.log('info', '策略: 刷新当前页面');
        await this.page.reload({ waitUntil: 'networkidle2', timeout: 30000 });
        await new Promise(resolve => setTimeout(resolve, 3000));
        break;
        
      case 'restart':
        // 重新开始流程（适用于刷新后回到初始状态的网站）
        this.log('warn', '策略: 刷新会重置，执行自定义恢复');
        await this.page.reload({ waitUntil: 'networkidle2', timeout: 30000 });
        await new Promise(resolve => setTimeout(resolve, 3000));
        
        // 调用站点特定的恢复方法
        if (this.onRestart && typeof this.onRestart === 'function') {
          const restartSteps = await this.onRestart(options);
          
          // 如果返回步骤索引/名称数组，则重新执行这些步骤
          if (Array.isArray(restartSteps) && restartSteps.length > 0) {
            await this.rerunSteps(restartSteps);
          }
        } else {
          this.log('warn', '未定义 onRestart 方法，跳过恢复步骤');
        }
        break;
        
      case 'wait':
        const waitTime = options.waitTime || 10000;
        this.log('info', `策略: 延长等待 ${waitTime}ms（第 ${retryCount} 次）`);
        await new Promise(resolve => setTimeout(resolve, waitTime));
        break;
        
      default:
        this.log('warn', `未知重试策略: ${strategy}，使用默认等待`);
        await new Promise(resolve => setTimeout(resolve, 5000));
    }
  }
  
  /**
   * 重启后的恢复钩子（子类重写）
   * @returns {Array|void} 返回需要重新执行的步骤名称/索引数组，或 void（自定义实现）
   */
  async onRestart(options) {
    this.log('debug', 'onRestart hook (未实现)');
  }
  
  /**
   * 重新执行指定的工作流步骤
   * @param {Array} stepIdentifiers - 步骤名称或索引数组
   */
  async rerunSteps(stepIdentifiers) {
    if (!this.context.engine) {
      this.log('error', '无法重新执行步骤：引擎未初始化');
      return;
    }
    
    this.log('info', `重新执行 ${stepIdentifiers.length} 个步骤...`);
    
    const workflowSteps = this.config.workflow || [];
    const stepsToRun = [];
    
    // 根据标识符查找步骤
    for (const identifier of stepIdentifiers) {
      if (typeof identifier === 'number') {
        // 按索引查找
        if (workflowSteps[identifier]) {
          stepsToRun.push(workflowSteps[identifier]);
        }
      } else if (typeof identifier === 'string') {
        // 按名称查找
        const step = workflowSteps.find(s => s.name === identifier);
        if (step) {
          stepsToRun.push(step);
        }
      }
    }
    
    if (stepsToRun.length === 0) {
      this.log('warn', '未找到要重新执行的步骤');
      return;
    }
    
    // 重新执行这些步骤
    for (const step of stepsToRun) {
      this.log('info', `→ 重新执行: ${step.name || step.action}`);
      await this.context.engine.executeAction(step);
    }
    
    this.log('success', `✓ 已重新执行 ${stepsToRun.length} 个步骤`);
  }
  
  /**
   * 执行入口
   * @returns {Promise<Object>}
   */
  async execute() {
    try {
      // 执行前钩子
      await this.beforeWorkflow();
      
      // 创建工作流引擎
      const engine = new WorkflowEngine(this.context, this.config);
      this.context.engine = engine;
      this.context.adapter = this;
      
      // 执行工作流
      const result = await engine.execute();
      
      // 执行后钩子
      await this.afterWorkflow();
      
      return result;
      
    } catch (error) {
      await this.onError(error);
      throw error;
    }
  }
  
  /**
   * 记录日志
   */
  log(level, message) {
    if (this.logger && this.logger[level]) {
      this.logger[level](this.siteName, message);
    } else {
      console.log(`[${level.toUpperCase()}] ${message}`);
    }
  }
}

module.exports = SiteAdapter;
