/**
 * 自定义测试报告 + AI 可读输出
 *
 * 作为 Playwright Reporter 收集结果，
 * 测试结束后生成 test-results/ai-summary.md（供 AI 编辑器解析）
 */
import type {
  Reporter, FullConfig, Suite, TestCase, TestResult, FullResult
} from '@playwright/test/reporter';
import fs from 'fs';
import path from 'path';

// ============================================================
//  测试结果数据结构
// ============================================================

export interface TestResultItem {
  id: string;
  name: string;
  status: 'passed' | 'failed' | 'skipped' | 'timedOut';
  duration: number;   // ms
  error?: string;
  screenshots?: string[];
}

export interface ModuleReport {
  module: string;
  tests: TestResultItem[];
  passed: number;
  failed: number;
  skipped: number;
  passRate: number;
}

export interface FullReport {
  timestamp: string;
  total: number;
  passed: number;
  failed: number;
  skipped: number;
  passRate: number;
  duration: number;
  modules: ModuleReport[];
}

// ============================================================
//  Playwright Custom Reporter
// ============================================================

class AISummaryReporter implements Reporter {
  private allResults: TestResultItem[] = [];
  private startTime = 0;
  private outputDir = '';

  onBegin(_config: FullConfig, suite: Suite) {
    this.startTime = Date.now();
    this.outputDir = _config.projects[0]?.outputDir || 'test-results';
    // 确保输出目录存在
    if (!fs.existsSync(this.outputDir)) {
      fs.mkdirSync(this.outputDir, { recursive: true });
    }
  }

  onTestEnd(test: TestCase, result: TestResult) {
    const titlePath = test.titlePath(); // e.g. ['前端核心页面 E2E', 'E01: ...']
    const module = titlePath.length > 1 ? titlePath.slice(0, -1).join(' › ') : '(顶层)';
    const name = titlePath[titlePath.length - 1];

    // 收集截图路径
    const screenshots: string[] = [];
    for (const attachment of result.attachments) {
      if (attachment.name === 'screenshot' && attachment.path) {
        screenshots.push(path.relative(process.cwd(), attachment.path));
      }
    }

    this.allResults.push({
      id: test.id,
      name: titlePath.join(' › '),
      status: result.status as TestResultItem['status'],
      duration: result.duration,
      error: result.error?.message?.split('\n')[0], // 只取第一行错误摘要
      screenshots,
    });
  }

  onEnd(result: FullResult) {
    const duration = Date.now() - this.startTime;
    const report = this.buildReport(duration);
    this.writeMarkdownSummary(report, result.status);
    this.writeJsonReport(report);
  }

  /** 构建结构化报告 */
  private buildReport(duration: number): FullReport {
    // 按模块分组
    const moduleMap = new Map<string, TestResultItem[]>();
    for (const r of this.allResults) {
      const mod = r.name.includes(' › ') ? r.name.split(' › ')[0] : '(顶层)';
      if (!moduleMap.has(mod)) moduleMap.set(mod, []);
      moduleMap.get(mod)!.push(r);
    }

    const modules: ModuleReport[] = [];
    for (const [name, tests] of moduleMap) {
      const passed = tests.filter(t => t.status === 'passed').length;
      const failed = tests.filter(t => t.status === 'failed').length;
      const skipped = tests.filter(t => t.status === 'skipped').length;
      modules.push({
        module: name,
        tests,
        passed, failed, skipped,
        passRate: tests.length ? Math.round((passed / tests.length) * 100) : 100,
      });
    }

    const passed = this.allResults.filter(t => t.status === 'passed').length;
    const failed = this.allResults.filter(t => t.status === 'failed').length;
    const skipped = this.allResults.filter(t => t.status === 'skipped').length;

    return {
      timestamp: new Date().toISOString(),
      total: this.allResults.length,
      passed, failed, skipped,
      passRate: this.allResults.length ? Math.round((passed / this.allResults.length) * 100) : 100,
      duration,
      modules,
    };
  }

  /** 生成 AI 可读的 Markdown 摘要 */
  private writeMarkdownSummary(report: FullReport, status: string) {
    const lines: string[] = [];

    lines.push('# 自动化测试报告');
    lines.push('');
    lines.push(`> 时间: ${report.timestamp}`);
    lines.push(`> 耗时: ${(report.duration / 1000).toFixed(1)}s`);
    lines.push(`> 状态: ${status === 'passed' ? '✅ 全部通过' : '❌ 存在失败'}`);
    lines.push('');

    // ---- 汇总表格 ----
    lines.push('## 汇总');
    lines.push('');
    lines.push('| 指标 | 值 |');
    lines.push('|------|-----|');
    lines.push(`| 用例总数 | ${report.total} |`);
    lines.push(`| 通过 | ${report.passed} |`);
    lines.push(`| 失败 | ${report.failed} |`);
    lines.push(`| 跳过 | ${report.skipped} |`);
    lines.push(`| 通过率 | **${report.passRate}%** |`);
    lines.push('');

    // ---- 按模块详情 ----
    for (const mod of report.modules) {
      const icon = mod.failed > 0 ? '❌' : '✅';
      lines.push(`## ${icon} ${mod.module}  (${mod.passed}/${mod.tests.length})`);
      lines.push('');
      lines.push('| 用例 | 结果 | 耗时 | 截图 |');
      lines.push('|------|------|------|------|');

      for (const t of mod.tests) {
        const shortName = t.name.split(' › ').pop() || t.name;
        const statusIcon = t.status === 'passed' ? '✅' : t.status === 'failed' ? '❌' : '⊘';
        const screenshots = t.screenshots?.length
          ? t.screenshots.map(s => `[📷](${s})`).join(' ')
          : '-';
        lines.push(`| ${shortName} | ${statusIcon} | ${(t.duration / 1000).toFixed(1)}s | ${screenshots} |`);
      }
      lines.push('');

      // 失败详情
      const failures = mod.tests.filter(t => t.status === 'failed');
      if (failures.length > 0) {
        lines.push('### 失败详情');
        lines.push('');
        for (const f of failures) {
          lines.push(`- **${f.name.split(' › ').pop()}**: ${f.error || '未知错误'}`);
        }
        lines.push('');
      }
    }

    // ---- 控制台输出 ----
    lines.push('---');
    lines.push('');

    // 同时输出到控制台
    const consoleOutput = [
      '',
      '='.repeat(60),
      `  ${status === 'passed' ? '✅' : '❌'} 测试完成 | ${report.passed}/${report.total} 通过 (${report.passRate}%) | ${(report.duration / 1000).toFixed(1)}s`,
      '='.repeat(60),
    ];
    if (report.failed > 0) {
      for (const mod of report.modules) {
        for (const t of mod.tests) {
          if (t.status === 'failed') {
            consoleOutput.push(`  ❌ ${t.name.split(' › ').pop()}: ${t.error || '未知'}`);
          }
        }
      }
    }
    console.log(consoleOutput.join('\n'));

    // 写入文件
    const filePath = path.join(this.outputDir, 'ai-summary.md');
    fs.writeFileSync(filePath, lines.join('\n'), 'utf-8');
    console.log(`\n  📄 AI 摘要报告: ${filePath}`);
  }

  /** 写入 JSON 报告 */
  private writeJsonReport(report: FullReport) {
    const filePath = path.join(this.outputDir, 'ai-summary.json');
    fs.writeFileSync(filePath, JSON.stringify(report, null, 2), 'utf-8');
  }
}

export default AISummaryReporter;

// ============================================================
//  向后兼容：模块报告工厂（供测试内手动使用）
// ============================================================

const allModules: ModuleReport[] = [];

export function createModuleReport(module: string): {
  addResult: (result: TestResultItem) => void;
  finalize: () => ModuleReport;
} {
  const tests: TestResultItem[] = [];
  return {
    addResult(result: TestResultItem) {
      tests.push(result);
    },
    finalize() {
      const passed = tests.filter(t => t.status === 'passed').length;
      const failed = tests.filter(t => t.status === 'failed').length;
      const skipped = tests.filter(t => t.status === 'skipped').length;
      const report: ModuleReport = { module, tests, passed, failed, skipped, passRate: tests.length ? Math.round((passed / tests.length) * 100) : 100 };
      allModules.push(report);
      return report;
    },
  };
}

export function generateFullReport(startTime: number): FullReport {
  const duration = Date.now() - startTime;
  const totalTests = allModules.reduce((s, m) => s + m.tests.length, 0);
  const totalPassed = allModules.reduce((s, m) => s + m.passed, 0);
  const totalFailed = allModules.reduce((s, m) => s + m.failed, 0);
  const totalSkipped = allModules.reduce((s, m) => s + m.skipped, 0);
  return {
    timestamp: new Date().toISOString(),
    total: totalTests, passed: totalPassed, failed: totalFailed, skipped: totalSkipped,
    passRate: totalTests ? Math.round((totalPassed / totalTests) * 100) : 100,
    duration, modules: allModules,
  };
}

export function printConsoleReport(report: FullReport) {
  const lines = [
    '', '='.repeat(60),
    `  ${report.passed}/${report.total} 通过 (${report.passRate}%) | ${(report.duration / 1000).toFixed(1)}s`,
    '='.repeat(60),
  ];
  for (const mod of report.modules) {
    lines.push(`  ${mod.failed > 0 ? '❌' : '✅'} ${mod.module}: ${mod.passed}/${mod.tests.length}`);
    for (const t of mod.tests) {
      if (t.status === 'failed') lines.push(`     ❌ ${t.name}: ${t.error || ''}`);
    }
  }
  if (report.failed) lines.push(`  ⚠ ${report.failed} 个失败用例`);
  else lines.push('  ✅ 全部通过');
  console.log(lines.join('\n'));
}

export function saveJsonReport(report: FullReport, outputDir: string) {
  if (!fs.existsSync(outputDir)) fs.mkdirSync(outputDir, { recursive: true });
  fs.writeFileSync(path.join(outputDir, `regression-report-${Date.now()}.json`), JSON.stringify(report, null, 2));
}

export function getExitCode(report: FullReport, threshold = 90): number {
  return report.passRate >= threshold ? 0 : 1;
}
