/**
 * 测试代码生成器
 * 负责将JSON测试描述转换为Cypress测试代码
 */

const fs = require('fs');
const path = require('path');
const TestTemplateEngine = require('./template-engine');
const config = require('./config');

class TestCodeGenerator {
  constructor() {
    this.templateEngine = new TestTemplateEngine();
    this.config = config;
  }

  /**
   * 从JSON描述生成测试代码
   * @param {object} testDescription - JSON测试描述
   * @returns {string} 生成的测试代码
   */
  generateFromJSON(testDescription) {
    // 验证JSON结构
    this.validateTestDescription(testDescription);

    const { testSuite } = testDescription;
    
    // 构建模板上下文
    const context = this.buildTemplateContext(testSuite);
    
    // 生成测试代码
    const testCode = this.generateTestCode(context);
    
    return testCode;
  }

  /**
   * 验证测试描述JSON结构
   */
  validateTestDescription(testDescription) {
    if (!testDescription.testSuite) {
      throw new Error('测试描述必须包含 testSuite 字段');
    }

    const { testSuite } = testDescription;
    
    if (!testSuite.name) {
      throw new Error('测试套件必须包含 name 字段');
    }

    if (!testSuite.module) {
      throw new Error('测试套件必须包含 module 字段');
    }

    if (!Array.isArray(testSuite.scenarios)) {
      throw new Error('测试套件必须包含 scenarios 数组');
    }

    // 验证模块是否在支持列表中
    if (!this.config.moduleRoutes[testSuite.module]) {
      throw new Error(`不支持的模块: ${testSuite.module}`);
    }
  }

  /**
   * 构建模板上下文
   */
  buildTemplateContext(testSuite) {
    const moduleId = this.config.moduleTestIds[testSuite.module];
    const routePath = this.config.moduleRoutes[testSuite.module];

    const context = {
      testSuiteName: testSuite.name,
      moduleId: moduleId,
      routePath: routePath,
      beforeEach: this.buildBeforeEachContext(testSuite.beforeEach, routePath, moduleId),
      scenarios: testSuite.scenarios.map(scenario => this.buildScenarioContext(scenario, moduleId))
    };

    return context;
  }

  /**
   * 构建beforeEach上下文
   */
  buildBeforeEachContext(beforeEach, routePath, moduleId) {
    const defaultBeforeEach = {
      login: true,
      visit: routePath,
      waitFor: [`[data-testid="${moduleId}-container"]`]
    };

    return { ...defaultBeforeEach, ...beforeEach };
  }

  /**
   * 构建场景上下文
   */
  buildScenarioContext(scenario, moduleId) {
    return {
      name: scenario.name,
      type: scenario.type,
      description: scenario.description,
      priority: scenario.priority || 'medium',
      steps: this.processSteps(scenario.steps, moduleId),
      expectedResults: this.processExpectedResults(scenario.expectedResults, moduleId)
    };
  }

  /**
   * 处理测试步骤
   */
  processSteps(steps, moduleId) {
    return steps.map(step => {
      const processedStep = { ...step };
      
      // 处理目标选择器
      if (step.target) {
        processedStep.target = this.processSelector(step.target, moduleId);
      }

      // 处理特定操作的附加逻辑
      switch (step.action) {
        case 'search':
          processedStep.action = 'custom';
          processedStep.customCommand = `cy.search${this.capitalize(moduleId)}Data`;
          break;
        case 'reset':
          processedStep.action = 'custom';
          processedStep.customCommand = `cy.reset${this.capitalize(moduleId)}Search`;
          break;
        case 'openDialog':
          processedStep.action = 'custom';
          processedStep.customCommand = `cy.openAnalysisDialog`;
          break;
      }

      return processedStep;
    });
  }

  /**
   * 处理期望结果
   */
  processExpectedResults(expectedResults, moduleId) {
    if (!expectedResults) return [];

    return expectedResults.map(result => {
      const processedResult = { ...result };
      
      if (result.target) {
        processedResult.target = this.processSelector(result.target, moduleId);
      }

      return processedResult;
    });
  }

  /**
   * 处理选择器，将占位符替换为实际值
   */
  processSelector(selector, moduleId) {
    // 替换 {module} 占位符
    let processedSelector = selector.replace(/\{module\}/g, moduleId);
    
    // 处理通用选择器
    Object.keys(this.config.commonSelectors).forEach(key => {
      const pattern = new RegExp(`\\{${key}\\}`, 'g');
      const selectorTemplate = this.config.commonSelectors[key];
      processedSelector = processedSelector.replace(pattern, selectorTemplate.replace(/\{module\}/g, moduleId));
    });

    return processedSelector;
  }

  /**
   * 生成测试代码
   */
  generateTestCode(context) {
    let testCode = '';

    // 生成文件头部
    testCode += `/// <reference types="cypress" />\n\n`;

    // 生成测试套件开始
    testCode += `describe('${context.testSuiteName}', () => {\n`;

    // 生成beforeEach块
    testCode += this.generateBeforeEach(context.beforeEach);

    // 生成测试场景
    context.scenarios.forEach(scenario => {
      testCode += this.generateScenario(scenario);
    });

    // 生成测试套件结束
    testCode += '})\n';

    return testCode;
  }

  /**
   * 生成beforeEach块
   */
  generateBeforeEach(beforeEachContext) {
    let beforeEachCode = '\n  beforeEach(() => {\n';

    if (beforeEachContext.login) {
      beforeEachCode += '    // 模拟登录状态\n';
      beforeEachCode += '    cy.mockLogin()\n';
    }

    if (beforeEachContext.visit) {
      beforeEachCode += '    \n';
      beforeEachCode += '    // 访问页面\n';
      beforeEachCode += `    cy.visit('/#/${beforeEachContext.visit}')\n`;
    }

    if (beforeEachContext.waitFor && beforeEachContext.waitFor.length > 0) {
      beforeEachCode += '    \n';
      beforeEachCode += '    // 等待页面加载完成\n';
      beforeEachContext.waitFor.forEach(selector => {
        beforeEachCode += `    cy.get('${selector}').should('be.visible')\n`;
      });
    }

    beforeEachCode += '  })\n\n';

    return beforeEachCode;
  }

  /**
   * 生成测试场景
   */
  generateScenario(scenario) {
    let scenarioCode = `  it('${scenario.name}', () => {\n`;

    // 生成测试步骤
    scenario.steps.forEach((step, index) => {
      if (index > 0) scenarioCode += '\n';
      scenarioCode += this.generateStep(step);
    });

    // 生成期望结果验证
    if (scenario.expectedResults && scenario.expectedResults.length > 0) {
      scenarioCode += '\n    // 验证结果\n';
      scenario.expectedResults.forEach(result => {
        scenarioCode += this.generateAssertion(result);
      });
    }

    scenarioCode += '  })\n\n';

    return scenarioCode;
  }

  /**
   * 生成测试步骤
   */
  generateStep(step) {
    let stepCode = '';

    if (step.description) {
      stepCode += `    // ${step.description}\n`;
    }

    switch (step.action) {
      case 'click':
        stepCode += `    cy.get('${step.target}').click()\n`;
        break;
      case 'type':
        const clearOption = step.options && step.options.clear ? '.clear()' : '';
        stepCode += `    cy.get('${step.target}')${clearOption}.type('${step.value}')\n`;
        break;
      case 'select':
        stepCode += `    cy.get('${step.target}').click()\n`;
        stepCode += `    cy.get('.el-select-dropdown__item').contains('${step.value}').click()\n`;
        break;
      case 'wait':
        stepCode += `    cy.wait(${step.value})\n`;
        break;
      case 'verify':
        stepCode += this.generateAssertion({
          target: step.target,
          assertion: step.value.assertion,
          value: step.value.value
        });
        break;
      case 'intercept':
        stepCode += this.generateIntercept(step.value);
        break;
      case 'custom':
        if (step.customCommand) {
          const params = step.value ? `('${step.value}')` : '()';
          stepCode += `    ${step.customCommand}${params}\n`;
        }
        break;
    }

    return stepCode;
  }

  /**
   * 生成断言
   */
  generateAssertion(assertion) {
    const notPrefix = assertion.not ? 'not.' : '';
    const valueParam = assertion.value ? `, '${assertion.value}'` : '';
    
    return `    cy.get('${assertion.target}').should('${notPrefix}${assertion.assertion}'${valueParam})\n`;
  }

  /**
   * 生成API拦截
   */
  generateIntercept(interceptConfig) {
    let interceptCode = `    cy.intercept('${interceptConfig.method}', '${interceptConfig.url}'`;
    
    if (interceptConfig.response) {
      interceptCode += `, ${JSON.stringify(interceptConfig.response)}`;
    } else if (interceptConfig.fixture) {
      interceptCode += `, { fixture: '${interceptConfig.fixture}' }`;
    }
    
    interceptCode += `).as('${interceptConfig.alias}')\n`;

    return interceptCode;
  }

  /**
   * 首字母大写
   */
  capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }

  /**
   * 生成测试文件
   * @param {object} testDescription - JSON测试描述
   * @param {string} outputPath - 输出文件路径
   */
  generateTestFile(testDescription, outputPath) {
    const testCode = this.generateFromJSON(testDescription);
    
    // 确保输出目录存在
    const outputDir = path.dirname(outputPath);
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir, { recursive: true });
    }

    // 写入文件
    fs.writeFileSync(outputPath, testCode, 'utf8');
    
    return outputPath;
  }
}

module.exports = TestCodeGenerator;