#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

// 读取合并后的报告数据
const reportPath = path.join(__dirname, '..', 'public', 'reports', 'merged-report.json');
const reportHtmlPath = path.join(__dirname, '..', 'public', 'reports', 'merged-report.html');

// 确保reports目录存在
const reportsDir = path.join(__dirname, '..', 'public', 'reports');
if (!fs.existsSync(reportsDir)) {
  fs.mkdirSync(reportsDir, { recursive: true });
}

// 读取报告数据
let reportData;
try {
  const rawData = fs.readFileSync(reportPath, 'utf8');
  reportData = JSON.parse(rawData);
} catch (error) {
  console.error('无法读取报告数据:', error);
  process.exit(1);
}

// 提取测试统计信息
const stats = reportData.stats;
const results = reportData.results;

// 按文件分组测试结果
const fileResults = {};
results.forEach(result => {
  const file = result.file || result.fullFile;
  if (file) {
    if (!fileResults[file]) {
      fileResults[file] = {
        tests: 0,
        passes: 0,
        failures: 0,
        pending: 0,
        duration: 0,
        testDetails: []
      };
    }
    
    // 遍历套件提取测试详情
    const extractTests = (suite) => {
      if (suite.tests && suite.tests.length > 0) {
        suite.tests.forEach(test => {
          fileResults[file].tests++;
          if (test.state === 'passed') fileResults[file].passes++;
          if (test.state === 'failed') fileResults[file].failures++;
          if (test.state === 'pending') fileResults[file].pending++;
          fileResults[file].duration += test.duration || 0;
          
          fileResults[file].testDetails.push({
            title: test.title,
            fullTitle: test.fullTitle,
            state: test.state,
            duration: test.duration,
            error: test.err && test.err.message ? test.err.message : null,
            uuid: test.uuid
          });
        });
      }
      
      if (suite.suites && suite.suites.length > 0) {
        suite.suites.forEach(subSuite => extractTests(subSuite));
      }
    };
    
    if (result.suites && result.suites.length > 0) {
      result.suites.forEach(suite => extractTests(suite));
    }
  }
});

// 生成HTML报告
const generateHtmlReport = () => {
  const fileEntries = Object.entries(fileResults);
  
  // 创建一个缓存来存储报告文件和测试文件的映射关系
  // 使用Map存储数组，一个测试文件可能对应多个报告文件
  const reportFileMap = new Map();
  
  // 创建一个函数来解析HTML报告文件并提取测试文件信息
  const parseReportFile = (reportFilePath) => {
    try {
      const content = fs.readFileSync(reportFilePath, 'utf8');
      // 使用正则表达式提取data-raw属性中的JSON数据
      const match = content.match(/data-raw="([^"]*)"/);
      if (match && match[1]) {
        // 解码HTML实体
        const decoded = match[1].replace(/&quot;/g, '"').replace(/&#x27;/g, "'");
        const rawData = JSON.parse(decoded);
        if (rawData.results && rawData.results.length > 0) {
          const testFile = rawData.results[0].fullFile || rawData.results[0].file;
          if (testFile) {
            return testFile;
          }
        }
      }
    } catch (error) {
      console.error(`解析报告文件时出错 ${reportFilePath}:`, error);
    }
    return null;
  };
  
  // 构建报告文件和测试文件的映射关系
  const buildReportMap = () => {
    const reportDir = path.join(__dirname, '..', 'cypress', 'reports');
    if (!fs.existsSync(reportDir)) {
      return;
    }
    
    const reportFiles = fs.readdirSync(reportDir).filter(file => file.endsWith('.html'));
    for (const reportFile of reportFiles) {
      const fullPath = path.join(reportDir, reportFile);
      const testFile = parseReportFile(fullPath);
      if (testFile) {
        // 如果该测试文件已经有报告文件，添加到数组中
        if (reportFileMap.has(testFile)) {
          reportFileMap.get(testFile).push(`../../cypress/reports/${reportFile}`);
        } else {
          // 否则创建新数组
          reportFileMap.set(testFile, [`../../cypress/reports/${reportFile}`]);
        }
      }
    }
  };
  
  // 构建映射关系
  buildReportMap();
  
  // 生成文件详情表格
  const generateFileDetails = () => {
    return fileEntries.map(([file, data]) => {
      // 生成跳转到原始报告的链接
      const fileName = path.basename(file);
      const originalReportLinks = reportFileMap.get(file) || [];
      
      // 生成所有报告文件的链接
      const reportLinksHtml = originalReportLinks.map((link, index) => {
        // 如果只有一个报告文件，使用默认文本
        if (originalReportLinks.length === 1) {
          return `<a href="${link}" target="_blank" class="report-link">查看原始报告</a>`;
        }
        // 如果有多个报告文件，添加序号
        return `<a href="${link}" target="_blank" class="report-link">查看原始报告 #${index + 1}</a>`;
      }).join(' ');
      
      return `
        <div class="file-details">
          <h3>
            ${fileName}
            ${reportLinksHtml}
          </h3>
          <div class="file-stats">
            <span class="stat passes">通过: ${data.passes}</span>
            <span class="stat failures">失败: ${data.failures}</span>
            <span class="stat pending">待定: ${data.pending}</span>
            <span class="stat duration">耗时: ${data.duration}ms</span>
          </div>
          <div class="test-list">
            ${data.testDetails.map(test => `
              <div class="test-item ${test.state}">
                <span class="test-title">${test.title}</span>
                <span class="test-duration">${test.duration}ms</span>
                ${test.error ? `<div class="test-error">${test.error}</div>` : ''}
              </div>
            `).join('')}
          </div>
        </div>
      `;
    }).join('');
  };
  
  // 生成统计图表数据
  const chartData = {
    labels: fileEntries.map(([file]) => path.basename(file)),
    passes: fileEntries.map(([, data]) => data.passes),
    failures: fileEntries.map(([, data]) => data.failures),
    pending: fileEntries.map(([, data]) => data.pending)
  };
  
  // 计算图表最大值用于比例计算
  const maxVal = Math.max(...chartData.passes, ...chartData.failures, ...chartData.pending, 1);
  
  // 生成CSS柱状图
  const generateBarChart = () => {
    return `
      <div class="chart-container">
        <div class="chart-header">
          <div class="legend">
            <div class="legend-item passes"><div class="legend-color"></div>通过</div>
            <div class="legend-item failures"><div class="legend-color"></div>失败</div>
            <div class="legend-item pending"><div class="legend-color"></div>待定</div>
          </div>
        </div>
        <div class="chart">
          ${chartData.labels.map((label, index) => {
            const passHeight = (chartData.passes[index] / maxVal) * 100;
            const failHeight = (chartData.failures[index] / maxVal) * 100;
            const pendHeight = (chartData.pending[index] / maxVal) * 100;
            const totalHeight = passHeight + failHeight + pendHeight;
            
            return `
              <div class="chart-bar">
                <div class="bar-label">${label}</div>
                <div class="bar-container">
                  <div class="bar-segment passes" style="height: ${passHeight}%;"></div>
                  <div class="bar-segment failures" style="height: ${failHeight}%;"></div>
                  <div class="bar-segment pending" style="height: ${pendHeight}%;"></div>
                </div>
                <div class="bar-value">${chartData.passes[index]}/${chartData.failures[index]}/${chartData.pending[index]}</div>
              </div>
            `;
          }).join('')}
        </div>
      </div>
    `;
  };
  
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试报告汇总</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
            line-height: 1.6;
            color: #333;
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .header {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
        .summary-stats {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 20px;
            margin: 20px 0;
        }
        .stat-card {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            text-align: center;
        }
        .stat-card.passes { border-top: 4px solid #4caf50; }
        .stat-card.failures { border-top: 4px solid #f44336; }
        .stat-card.pending { border-top: 4px solid #ff9800; }
        .stat-card.total { border-top: 4px solid #2196f3; }
        .stat-card .number {
            font-size: 2em;
            font-weight: bold;
            margin: 10px 0;
        }
        .chart-container {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
        .chart-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
        }
        .legend {
            display: flex;
            gap: 20px;
        }
        .legend-item {
            display: flex;
            align-items: center;
            gap: 5px;
        }
        .legend-color {
            width: 20px;
            height: 20px;
            border-radius: 3px;
        }
        .legend-item.passes .legend-color { background-color: #4caf50; }
        .legend-item.failures .legend-color { background-color: #f44336; }
        .legend-item.pending .legend-color { background-color: #ff9800; }
        .chart {
            display: flex;
            gap: 10px;
            overflow-x: auto;
            padding: 20px 0;
            flex-wrap: wrap;
        }
        .chart-bar {
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 80px;
        }
        .bar-label {
            margin-bottom: 10px;
            text-align: center;
            font-size: 11px;
            line-height: 12px;
            height: 40px;
        }
        .bar-container {
            display: flex;
            flex-direction: column-reverse;
            width: 40px;
            height: 200px;
            background-color: #f0f0f0;
            border-radius: 3px;
            overflow: hidden;
        }
        .bar-segment {
            width: 100%;
            transition: height 0.3s ease;
        }
        .bar-segment.passes { background-color: #4caf50; }
        .bar-segment.failures { background-color: #f44336; }
        .bar-segment.pending { background-color: #ff9800; }
        .bar-value {
            margin-top: 10px;
            font-size: 12px;
            text-align: center;
        }
        .file-details {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            margin-bottom: 20px;
        }
        .file-stats {
            display: flex;
            gap: 15px;
            margin: 10px 0;
            flex-wrap: wrap;
        }
        .stat {
            padding: 5px 10px;
            border-radius: 4px;
            font-weight: bold;
        }
        .stat.passes { background-color: #e8f5e9; color: #4caf50; }
        .stat.failures { background-color: #ffebee; color: #f44336; }
        .stat.pending { background-color: #fff3e0; color: #ff9800; }
        .stat.duration { background-color: #e3f2fd; color: #2196f3; }
        .test-list {
            margin-top: 15px;
        }
        .test-item {
            padding: 10px;
            border-bottom: 1px solid #eee;
        }
        .test-item:last-child {
            border-bottom: none;
        }
        .test-item.passed { border-left: 4px solid #4caf50; }
        .test-item.failed { border-left: 4px solid #f44336; }
        .test-item.pending { border-left: 4px solid #ff9800; }
        .test-title {
            font-weight: bold;
        }
        .test-duration {
            float: right;
            color: #666;
        }
        .test-error {
            color: #f44336;
            font-size: 0.9em;
            margin-top: 5px;
            white-space: pre-wrap;
        }
        h1, h2, h3 {
            color: #333;
        }
        h1 {
            text-align: center;
            margin-bottom: 30px;
        }
        h2 {
            border-bottom: 2px solid #eee;
            padding-bottom: 10px;
        }
        .report-link {
            float: right;
            font-size: 0.8em;
            color: #2196f3;
            text-decoration: none;
            border: 1px solid #2196f3;
            padding: 2px 8px;
            border-radius: 4px;
        }
        .report-link:hover {
            background-color: #2196f3;
            color: white;
        }
        @media (max-width: 768px) {
            .chart {
                gap: 15px;
            }
            .chart-bar {
                min-width: 60px;
            }
            .bar-container {
                width: 30px;
                height: 150px;
            }
        }
    </style>
</head>
<body>
    <div class="header">
        <h1>测试报告汇总</h1>
        <p>生成时间: ${new Date().toLocaleString('zh-CN')}</p>
    </div>
    
    <div class="summary-stats">
        <div class="stat-card passes">
            <div>通过测试</div>
            <div class="number">${stats.passes}</div>
            <div>${(stats.passPercent || 0).toFixed(2)}%</div>
        </div>
        <div class="stat-card failures">
            <div>失败测试</div>
            <div class="number">${stats.failures}</div>
        </div>
        <div class="stat-card pending">
            <div>待定测试</div>
            <div class="number">${stats.pending}</div>
        </div>
        <div class="stat-card total">
            <div>总测试数</div>
            <div class="number">${stats.tests}</div>
        </div>
    </div>
    
    <h2>测试结果分布</h2>
    ${generateBarChart()}
    
    <h2>详细测试结果</h2>
    ${generateFileDetails()}
</body>
</html>
  `;
};

// 生成并保存HTML报告
const htmlReport = generateHtmlReport();
const summaryReportPath = path.join(reportsDir, 'summary-report.html');
fs.writeFileSync(summaryReportPath, htmlReport);

console.log(`测试报告汇总已生成: ${summaryReportPath}`);

// 如果存在原始的merged-report.html，也复制一份作为备份
if (fs.existsSync(reportHtmlPath)) {
  const backupPath = path.join(reportsDir, 'merged-report-original.html');
  fs.copyFileSync(reportHtmlPath, backupPath);
  console.log(`原始报告已备份至: ${backupPath}`);
}