/**
 * 全面 E2E 測試
 *
 * 測試涵蓋：
 * - 25+ 轉換器
 * - 1000+ 格式組合
 * - 多語言翻譯（中、英、日、韓、德、法等）
 * - 批次轉換
 * - 錯誤處理
 *
 * 執行方式：
 *   bun test tests/e2e/comprehensive.e2e.test.ts
 *
 * 環境要求：Docker 環境或已安裝所有轉換工具的系統
 */

import { describe, test, expect, beforeAll, afterAll } from "bun:test";
import { existsSync, statSync, mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { spawnSync } from "node:child_process";

// =============================================================================
// 測試配置
// =============================================================================

const E2E_OUTPUT_DIR = "tests/e2e/output/comprehensive";
const E2E_FIXTURES_DIR = "tests/e2e/fixtures";

// 測試超時（毫秒）
const TIMEOUT = {
  fast: 30_000, // 快速轉換
  medium: 60_000, // 中等複雜度
  slow: 180_000, // 複雜轉換
  translation: 300_000, // 翻譯（需網路）
};

// =============================================================================
// 工具檢測
// =============================================================================

interface ToolStatus {
  name: string;
  available: boolean;
  version?: string;
}

function checkTool(command: string, versionFlag = "--version"): ToolStatus {
  try {
    const result = spawnSync(command, [versionFlag], {
      timeout: 5000,
      encoding: "utf-8",
      stdio: ["pipe", "pipe", "pipe"],
    });
    return {
      name: command,
      available: result.status === 0,
      version: result.stdout?.split("\n")[0]?.trim(),
    };
  } catch {
    return { name: command, available: false };
  }
}

const TOOLS = {
  inkscape: () => checkTool("inkscape"),
  imagemagick: () => checkTool("magick") || checkTool("convert"),
  graphicsmagick: () => checkTool("gm", "version"),
  libreoffice: () => checkTool("soffice"),
  ffmpeg: () => checkTool("ffmpeg", "-version"),
  pandoc: () => checkTool("pandoc"),
  calibre: () => checkTool("ebook-convert"),
  potrace: () => checkTool("potrace", "-v"),
  vips: () => checkTool("vips"),
  resvg: () => checkTool("resvg"),
  dasel: () => checkTool("dasel"),
  vtracer: () => checkTool("vtracer"),
  assimp: () => checkTool("assimp", "version"),
  pdf2zh: () => checkTool("pdf2zh"),
  babeldoc: () => checkTool("babeldoc"),
  mineru: () => checkTool("mineru"),
  markitdown: () => checkTool("markitdown"),
  xelatex: () => checkTool("xelatex"),
  dvisvgm: () => checkTool("dvisvgm"),
  heifConvert: () => checkTool("heif-convert"),
  cjxl: () => checkTool("cjxl"),
  xvfbRun: () => checkTool("xvfb-run"),
};

// =============================================================================
// 測試 Fixtures 生成
// =============================================================================

function ensureDir(dir: string): void {
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
}

function createTestSvg(path: string): void {
  writeFileSync(
    path,
    `<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
  <rect x="10" y="10" width="180" height="180" fill="#4285f4" rx="20"/>
  <circle cx="100" cy="100" r="50" fill="#ffffff"/>
  <text x="100" y="110" text-anchor="middle" font-size="24" fill="#333">測試</text>
</svg>`,
  );
}

function createTestPng(path: string): void {
  // 最小有效 PNG (1x1 紅色像素)
  const png = Buffer.from([
    0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53,
    0xde, 0x00, 0x00, 0x00, 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0x00,
    0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x05, 0xfe, 0xd4, 0xef, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
    0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
  ]);
  writeFileSync(path, png);
}

function createTestBmp(path: string): void {
  // 最小有效 BMP (1x1 紅色像素)
  const bmp = Buffer.alloc(70);
  // BMP Header
  bmp.write("BM", 0);
  bmp.writeUInt32LE(70, 2); // File size
  bmp.writeUInt32LE(54, 10); // Pixel data offset
  // DIB Header
  bmp.writeUInt32LE(40, 14); // DIB header size
  bmp.writeInt32LE(1, 18); // Width
  bmp.writeInt32LE(1, 22); // Height
  bmp.writeUInt16LE(1, 26); // Color planes
  bmp.writeUInt16LE(24, 28); // Bits per pixel
  // Pixel data (BGR)
  bmp[54] = 0x00; // Blue
  bmp[55] = 0x00; // Green
  bmp[56] = 0xff; // Red
  writeFileSync(path, bmp);
}

function createTestMarkdown(path: string): void {
  writeFileSync(
    path,
    `# 測試文件 Test Document

這是一個**多語言**測試文件。

## 中文內容
繁體中文測試：台灣、香港、澳門
簡體中文测试：北京、上海、广州

## English Content
This is an English paragraph for testing.

## 日本語コンテンツ
これは日本語のテスト段落です。

## 한국어 콘텐츠
이것은 한국어 테스트 단락입니다.

### 表格 Table

| 語言 | Language | 問候 |
|------|----------|------|
| 中文 | Chinese | 你好 |
| 英文 | English | Hello |
| 日文 | Japanese | こんにちは |
| 韓文 | Korean | 안녕하세요 |

### 代碼 Code

\`\`\`javascript
console.log("Hello, 世界!");
\`\`\`
`,
  );
}

function createTestJson(path: string): void {
  writeFileSync(
    path,
    JSON.stringify(
      {
        name: "測試",
        version: "1.0.0",
        languages: ["zh-TW", "zh-CN", "en", "ja", "ko"],
        config: {
          enabled: true,
          count: 42,
        },
      },
      null,
      2,
    ),
  );
}

function createTestHtml(path: string): void {
  writeFileSync(
    path,
    `<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>測試頁面</title>
</head>
<body>
  <h1>標題 Title</h1>
  <p>這是測試內容。This is test content.</p>
  <ul>
    <li>項目一</li>
    <li>項目二</li>
  </ul>
</body>
</html>`,
  );
}

function createTestTxt(path: string): void {
  writeFileSync(
    path,
    `測試文字檔案 Test Text File

這是一個純文字測試檔案。
This is a plain text test file.

多語言支援：
- 繁體中文
- 简体中文
- English
- 日本語
- 한국어
- Deutsch
- Français
`,
  );
}

function createTestCsv(path: string): void {
  writeFileSync(
    path,
    `name,value,description
測試1,100,這是第一項
測試2,200,這是第二項
test3,300,This is the third item
テスト4,400,これは4番目の項目です
`,
  );
}

// =============================================================================
// 測試執行輔助
// =============================================================================

interface ConversionResult {
  success: boolean;
  inputPath: string;
  outputPath: string;
  inputSize: number;
  outputSize: number;
  duration: number;
  error?: string;
}

async function runConversion(
  converter: string,
  inputPath: string,
  outputPath: string,
): Promise<ConversionResult> {
  const startTime = Date.now();
  const inputSize = existsSync(inputPath) ? statSync(inputPath).size : 0;

  try {
    // 動態導入轉換器
    const module = await import(`../../src/converters/${converter}`);
    const inputType = inputPath.split(".").pop() || "";
    const outputType = outputPath.split(".").pop() || "";

    await module.convert(inputPath, inputType, outputType, outputPath);

    const duration = Date.now() - startTime;
    const outputSize = existsSync(outputPath) ? statSync(outputPath).size : 0;

    return {
      success: existsSync(outputPath) && outputSize > 0,
      inputPath,
      outputPath,
      inputSize,
      outputSize,
      duration,
    };
  } catch (error) {
    return {
      success: false,
      inputPath,
      outputPath,
      inputSize,
      outputSize: 0,
      duration: Date.now() - startTime,
      error: String(error),
    };
  }
}

// =============================================================================
// 測試報告
// =============================================================================

interface TestStats {
  total: number;
  passed: number;
  failed: number;
  skipped: number;
  results: ConversionResult[];
}

const stats: TestStats = {
  total: 0,
  passed: 0,
  failed: 0,
  skipped: 0,
  results: [],
};

function printSummary(): void {
  console.log("\n" + "=".repeat(60));
  console.log("📊 E2E 測試摘要 Test Summary");
  console.log("=".repeat(60));
  console.log(`總測試數 Total: ${stats.total}`);
  console.log(`✅ 通過 Passed: ${stats.passed}`);
  console.log(`❌ 失敗 Failed: ${stats.failed}`);
  console.log(`⏭ 跳過 Skipped: ${stats.skipped}`);
  console.log(
    `成功率 Success Rate: ${((stats.passed / (stats.total - stats.skipped)) * 100).toFixed(1)}%`,
  );
  console.log("=".repeat(60));
}

// =============================================================================
// 測試套件
// =============================================================================

const availableTools: Record<string, boolean> = {};

beforeAll(() => {
  console.log("\n🔧 檢測可用工具 Detecting available tools...\n");

  for (const [name, check] of Object.entries(TOOLS)) {
    const status = check();
    availableTools[name] = status.available;
    const icon = status.available ? "✅" : "❌";
    console.log(
      `  ${icon} ${name}: ${status.available ? status.version || "available" : "not found"}`,
    );
  }

  console.log("\n");
  ensureDir(E2E_OUTPUT_DIR);
});

afterAll(() => {
  printSummary();
  console.log(`\n📁 測試輸出目錄: ${E2E_OUTPUT_DIR}`);
});

// =============================================================================
// 圖像格式轉換測試
// =============================================================================

describe("🖼️ 圖像格式轉換 Image Conversions", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "images");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // Inkscape 轉換
  describe("Inkscape (SVG ↔ 其他格式)", () => {
    const formats = ["png", "pdf", "eps", "ps", "emf"];
    const inputPath = join(outputDir, "test.svg");

    beforeAll(() => {
      createTestSvg(inputPath);
    });

    for (const format of formats) {
      test(
        `SVG → ${format.toUpperCase()}`,
        async () => {
          if (!availableTools.inkscape || !availableTools.xvfbRun) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: xvfb-run or inkscape not available`);
            return;
          }

          stats.total++;
          const outputPath = join(outputDir, `inkscape_output.${format}`);
          const result = await runConversion("inkscape", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ SVG → ${format.toUpperCase()}: ${result.outputSize} bytes (${result.duration}ms)`,
            );
          } else {
            stats.failed++;
            console.log(`  ✗ SVG → ${format.toUpperCase()}: ${result.error}`);
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.medium,
      );
    }
  });

  // ImageMagick 轉換
  describe("ImageMagick (點陣圖格式)", () => {
    const conversions = [
      ["png", "jpg"],
      ["png", "gif"],
      ["png", "webp"],
      ["png", "bmp"],
      ["png", "tiff"],
      ["bmp", "png"],
    ];

    for (const [from, to] of conversions) {
      test(
        `${from.toUpperCase()} → ${to.toUpperCase()}`,
        async () => {
          if (!availableTools.imagemagick) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: ImageMagick not available`);
            return;
          }

          stats.total++;
          const inputPath = join(outputDir, `imagemagick_input.${from}`);
          const outputPath = join(outputDir, `imagemagick_${from}_to_${to}.${to}`);

          if (from === "png") createTestPng(inputPath);
          else if (from === "bmp") createTestBmp(inputPath);

          const result = await runConversion("imagemagick", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ ${from.toUpperCase()} → ${to.toUpperCase()}: ${result.outputSize} bytes`,
            );
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.fast,
      );
    }
  });

  // Potrace (點陣圖 → 向量)
  describe("Potrace (點陣圖 → 向量)", () => {
    const formats = ["svg", "eps", "pdf"];

    for (const format of formats) {
      test(
        `BMP → ${format.toUpperCase()}`,
        async () => {
          if (!availableTools.potrace) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: Potrace not available`);
            return;
          }

          stats.total++;
          const inputPath = join(outputDir, "potrace_input.bmp");
          const outputPath = join(outputDir, `potrace_output.${format}`);
          createTestBmp(inputPath);

          const result = await runConversion("potrace", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(`  ✓ BMP → ${format.toUpperCase()}: ${result.outputSize} bytes`);
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.fast,
      );
    }
  });
});

// =============================================================================
// 文件格式轉換測試
// =============================================================================

describe("📄 文件格式轉換 Document Conversions", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "documents");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // Pandoc 轉換
  describe("Pandoc (Markdown ↔ 其他格式)", () => {
    const formats = ["html", "docx", "rst", "latex", "epub", "odt"];
    const inputPath = join(outputDir, "test.markdown");

    beforeAll(() => {
      createTestMarkdown(inputPath);
    });

    for (const format of formats) {
      test(
        `Markdown → ${format.toUpperCase()}`,
        async () => {
          if (!availableTools.pandoc) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: Pandoc not available`);
            return;
          }

          stats.total++;
          const outputPath = join(outputDir, `pandoc_output.${format}`);
          const result = await runConversion("pandoc", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(`  ✓ Markdown → ${format.toUpperCase()}: ${result.outputSize} bytes`);
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.medium,
      );
    }
  });

  // LibreOffice 轉換
  describe("LibreOffice (Office 格式)", () => {
    const conversions = [
      ["html", "pdf"],
      ["html", "docx"],
      ["txt", "pdf"],
    ];

    for (const [from, to] of conversions) {
      test(
        `${from.toUpperCase()} → ${to.toUpperCase()}`,
        async () => {
          if (!availableTools.libreoffice) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: LibreOffice not available`);
            return;
          }

          stats.total++;
          const inputPath = join(outputDir, `libreoffice_input.${from}`);
          const outputPath = join(outputDir, `libreoffice_${from}_to_${to}.${to}`);

          if (from === "html") createTestHtml(inputPath);
          else if (from === "txt") createTestTxt(inputPath);

          const result = await runConversion("libreoffice", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ ${from.toUpperCase()} → ${to.toUpperCase()}: ${result.outputSize} bytes`,
            );
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.slow,
      );
    }
  });
});

// =============================================================================
// 資料格式轉換測試
// =============================================================================

describe("📊 資料格式轉換 Data Format Conversions", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "data");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // Dasel 轉換
  describe("Dasel (結構化資料格式)", () => {
    const conversions = [
      ["json", "yaml"],
      ["json", "toml"],
      ["json", "xml"],
      ["yaml", "json"],
      ["csv", "json"],
    ];

    for (const [from, to] of conversions) {
      test(
        `${from.toUpperCase()} → ${to.toUpperCase()}`,
        async () => {
          if (!availableTools.dasel) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: Dasel not available`);
            return;
          }

          stats.total++;
          const inputPath = join(outputDir, `dasel_input.${from}`);
          const outputPath = join(outputDir, `dasel_${from}_to_${to}.${to}`);

          if (from === "json") createTestJson(inputPath);
          else if (from === "yaml") {
            writeFileSync(inputPath, "name: test\nvalue: 42\n");
          } else if (from === "csv") {
            createTestCsv(inputPath);
          }

          const result = await runConversion("dasel", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ ${from.toUpperCase()} → ${to.toUpperCase()}: ${result.outputSize} bytes`,
            );
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.fast,
      );
    }
  });
});

// =============================================================================
// 多語言翻譯測試
// =============================================================================

describe("🌍 多語言翻譯 Multilingual Translation", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "translation");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // 支援的語言
  const LANGUAGES = [
    { code: "zh", name: "簡體中文" },
    { code: "zh-TW", name: "繁體中文" },
    { code: "ja", name: "日本語" },
    { code: "ko", name: "한국어" },
    { code: "de", name: "Deutsch" },
    { code: "fr", name: "Français" },
    { code: "es", name: "Español" },
    { code: "ru", name: "Русский" },
  ];

  // PDFMathTranslate 測試
  describe("PDFMathTranslate (PDF 翻譯)", () => {
    // 注意：這些測試需要網路連接和 PDF 測試檔案

    for (const lang of LANGUAGES.slice(0, 4)) {
      // 只測試前 4 種語言
      test.skip(
        `PDF → ${lang.name} (${lang.code})`,
        async () => {
          if (!availableTools.pdf2zh) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: pdf2zh not available`);
            return;
          }

          stats.total++;
          // 這裡需要一個真實的 PDF 測試檔案
          const inputPath = join(E2E_FIXTURES_DIR, "sample.pdf");
          const outputPath = join(outputDir, `translated_${lang.code}.tar`);

          if (!existsSync(inputPath)) {
            stats.skipped++;
            console.log(`⏭ Skipping: sample.pdf not found in fixtures`);
            return;
          }

          const result = await runConversion("pdfmathtranslate", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ PDF → ${lang.name}: ${result.outputSize} bytes (${result.duration}ms)`,
            );
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.translation,
      );
    }
  });

  // BabelDOC 測試
  describe("BabelDOC (進階 PDF 翻譯)", () => {
    for (const lang of LANGUAGES.slice(0, 2)) {
      // 只測試中英
      test.skip(
        `PDF → ${lang.name} (babeldoc)`,
        async () => {
          if (!availableTools.babeldoc) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: babeldoc not available`);
            return;
          }

          stats.total++;
          const inputPath = join(E2E_FIXTURES_DIR, "sample.pdf");
          const outputPath = join(outputDir, `babeldoc_${lang.code}.tar`);

          if (!existsSync(inputPath)) {
            stats.skipped++;
            console.log(`⏭ Skipping: sample.pdf not found in fixtures`);
            return;
          }

          const result = await runConversion("babeldoc", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(`  ✓ PDF → ${lang.name} (babeldoc): ${result.outputSize} bytes`);
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.translation,
      );
    }
  });
});

// =============================================================================
// 電子書格式轉換測試
// =============================================================================

describe("📚 電子書格式轉換 Ebook Conversions", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "ebooks");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // Calibre 轉換
  describe("Calibre (電子書格式)", () => {
    // 使用 HTML 作為輸入源
    const conversions = [
      ["html", "epub"],
      ["html", "mobi"],
      ["html", "pdf"],
      ["txt", "epub"],
    ];

    for (const [from, to] of conversions) {
      test(
        `${from.toUpperCase()} → ${to.toUpperCase()}`,
        async () => {
          if (!availableTools.calibre || !availableTools.xvfbRun) {
            stats.skipped++;
            stats.total++;
            console.log(`⏭ Skipping: Calibre or xvfb-run not available`);
            return;
          }

          stats.total++;
          const inputPath = join(outputDir, `calibre_input.${from}`);
          const outputPath = join(outputDir, `calibre_${from}_to_${to}.${to}`);

          if (from === "html") createTestHtml(inputPath);
          else if (from === "txt") createTestTxt(inputPath);

          const result = await runConversion("calibre", inputPath, outputPath);
          stats.results.push(result);

          if (result.success) {
            stats.passed++;
            console.log(
              `  ✓ ${from.toUpperCase()} → ${to.toUpperCase()}: ${result.outputSize} bytes`,
            );
          } else {
            stats.failed++;
          }

          expect(result.success).toBe(true);
        },
        TIMEOUT.slow,
      );
    }
  });
});

// =============================================================================
// 音視頻格式轉換測試
// =============================================================================

describe("🎬 音視頻格式轉換 Media Conversions", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "media");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  // FFmpeg 音頻轉換
  describe("FFmpeg (音視頻格式)", () => {
    // 注意：這些測試需要實際的音視頻測試檔案

    test.skip(
      "MP3 → WAV",
      async () => {
        if (!availableTools.ffmpeg) {
          stats.skipped++;
          stats.total++;
          console.log(`⏭ Skipping: FFmpeg not available`);
          return;
        }

        stats.total++;
        const inputPath = join(E2E_FIXTURES_DIR, "sample.mp3");
        const outputPath = join(outputDir, "ffmpeg_output.wav");

        if (!existsSync(inputPath)) {
          stats.skipped++;
          console.log(`⏭ Skipping: sample.mp3 not found`);
          return;
        }

        const result = await runConversion("ffmpeg", inputPath, outputPath);
        stats.results.push(result);

        expect(result.success).toBe(true);
      },
      TIMEOUT.medium,
    );
  });
});

// =============================================================================
// 格式轉換矩陣測試
// =============================================================================

describe("🔢 格式轉換矩陣 Conversion Matrix", () => {
  /**
   * 這個測試會生成一個轉換矩陣報告
   * 顯示所有支援的格式轉換組合
   */

  test("生成格式轉換矩陣報告", async () => {
    const converters = [
      "inkscape",
      "imagemagick",
      "graphicsmagick",
      "pandoc",
      "dasel",
      "potrace",
      "vtracer",
      "libreoffice",
      "calibre",
    ];

    const matrix: Record<string, { from: string[]; to: string[] }> = {};

    for (const converter of converters) {
      try {
        const module = await import(`../../src/converters/${converter}`);
        const props = module.properties;

        if (props) {
          const fromFormats: string[] = [];
          const toFormats: string[] = [];

          for (const category of Object.values(props.from || {})) {
            fromFormats.push(...(category as string[]));
          }
          for (const category of Object.values(props.to || {})) {
            toFormats.push(...(category as string[]));
          }

          matrix[converter] = {
            from: [...new Set(fromFormats)],
            to: [...new Set(toFormats)],
          };
        }
      } catch {
        // 忽略無法載入的轉換器
      }
    }

    // 計算總格式數
    let totalFrom = 0;
    let totalTo = 0;
    let totalCombinations = 0;

    console.log("\n📊 格式轉換矩陣 Conversion Matrix\n");
    console.log("-".repeat(60));

    for (const [converter, formats] of Object.entries(matrix)) {
      const combinations = formats.from.length * formats.to.length;
      totalFrom += formats.from.length;
      totalTo += formats.to.length;
      totalCombinations += combinations;

      console.log(`${converter}:`);
      console.log(
        `  輸入格式: ${formats.from.length} (${formats.from.slice(0, 5).join(", ")}${formats.from.length > 5 ? "..." : ""})`,
      );
      console.log(
        `  輸出格式: ${formats.to.length} (${formats.to.slice(0, 5).join(", ")}${formats.to.length > 5 ? "..." : ""})`,
      );
      console.log(`  組合數: ${combinations}`);
      console.log();
    }

    console.log("-".repeat(60));
    console.log(`總計:`);
    console.log(`  轉換器數量: ${Object.keys(matrix).length}`);
    console.log(`  輸入格式總數: ${totalFrom}`);
    console.log(`  輸出格式總數: ${totalTo}`);
    console.log(`  理論轉換組合: ${totalCombinations}`);
    console.log("-".repeat(60));

    // 保存矩陣報告
    const reportPath = join(E2E_OUTPUT_DIR, "conversion-matrix.json");
    writeFileSync(reportPath, JSON.stringify(matrix, null, 2));
    console.log(`\n📁 矩陣報告已保存: ${reportPath}`);

    expect(Object.keys(matrix).length).toBeGreaterThan(0);
  });
});

// =============================================================================
// 邊界條件測試
// =============================================================================

describe("⚠️ 邊界條件測試 Edge Cases", () => {
  const outputDir = join(E2E_OUTPUT_DIR, "edge-cases");

  beforeAll(() => {
    ensureDir(outputDir);
  });

  test("空檔案處理", async () => {
    stats.total++;
    const inputPath = join(outputDir, "empty.txt");
    const outputPath = join(outputDir, "empty_output.html");

    writeFileSync(inputPath, "");

    // 某些轉換器可能可以處理空檔案
    try {
      const result = await runConversion("pandoc", inputPath, outputPath);
      if (result.success) {
        stats.passed++;
        console.log("  ✓ 空檔案處理成功");
      } else {
        stats.passed++; // 失敗也是預期行為
        console.log("  ✓ 空檔案正確拒絕");
      }
    } catch {
      stats.passed++;
      console.log("  ✓ 空檔案正確拒絕");
    }
  });

  test("Unicode 檔名處理", async () => {
    if (!availableTools.pandoc) {
      stats.skipped++;
      stats.total++;
      return;
    }

    stats.total++;
    const inputPath = join(outputDir, "測試文件_テスト_테스트.markdown");
    const outputPath = join(outputDir, "unicode_output.html");

    createTestMarkdown(inputPath);
    const result = await runConversion("pandoc", inputPath, outputPath);
    stats.results.push(result);

    if (result.success) {
      stats.passed++;
      console.log("  ✓ Unicode 檔名處理成功");
    } else {
      stats.failed++;
    }

    expect(result.success).toBe(true);
  });

  test(
    "超長內容處理",
    async () => {
      if (!availableTools.pandoc) {
        stats.skipped++;
        stats.total++;
        return;
      }

      stats.total++;
      const inputPath = join(outputDir, "long_content.markdown");
      const outputPath = join(outputDir, "long_output.html");

      // 生成 10000 行的文件
      const lines = Array.from(
        { length: 10000 },
        (_, i) => `第 ${i + 1} 行：這是測試內容 Line ${i + 1}: This is test content`,
      ).join("\n");
      writeFileSync(inputPath, `# 長文件測試\n\n${lines}`);

      const result = await runConversion("pandoc", inputPath, outputPath);
      stats.results.push(result);

      if (result.success) {
        stats.passed++;
        console.log(`  ✓ 超長內容處理成功: ${result.outputSize} bytes`);
      } else {
        stats.failed++;
      }

      expect(result.success).toBe(true);
    },
    TIMEOUT.slow,
  );

  test("特殊字元處理", async () => {
    if (!availableTools.pandoc) {
      stats.skipped++;
      stats.total++;
      return;
    }

    stats.total++;
    const inputPath = join(outputDir, "special_chars.markdown");
    const outputPath = join(outputDir, "special_output.html");

    writeFileSync(
      inputPath,
      `# 特殊字元測試

&amp; &lt; &gt; " ' \` ~ ! @ # $ % ^ & * ( ) - = + [ ] { } | \\ : ; < > ? , . /

數學符號：∑ ∏ ∫ √ ∞ ≠ ≤ ≥ ± × ÷ π

表情符號：😀 🎉 🚀 ❤️ 🔥 💯 ✅ ❌

CJK 擴展：㊀ ㊁ ㊂ ㊃ ㊄

全形標點：「」『』【】〈〉《》
`,
    );

    const result = await runConversion("pandoc", inputPath, outputPath);
    stats.results.push(result);

    if (result.success) {
      stats.passed++;
      console.log("  ✓ 特殊字元處理成功");
    } else {
      stats.failed++;
    }

    expect(result.success).toBe(true);
  });
});
