Source: utils/exportFormats.js

/**
 * @module utils/exportFormats
 * @description Enterprise test export format builders.
 *
 * Converts test objects into industry-standard formats for import into
 * external test management and CI tools.
 *
 * ### Supported formats
 * | Format       | Use case                                          |
 * |--------------|---------------------------------------------------|
 * | Zephyr CSV   | Zephyr Scale / Zephyr Squad test management       |
 * | TestRail CSV | TestRail bulk import                              |
 *
 * ### Exports
 * - {@link buildZephyrCsv} — Generate Zephyr Scale CSV from test array.
 * - {@link buildTestRailCsv} — Generate TestRail CSV from test array.
 */

// ── Zephyr Scale CSV ─────────────────────────────────────────────────────────
// Zephyr Scale (formerly TM4J) CSV import format for Jira.
// See: https://support.smartbear.com/zephyr-scale-cloud/docs/test-management/import-export/

/**
 * buildZephyrCsv(tests) → string (CSV)
 *
 * Produces a CSV compatible with Zephyr Scale's "Import Test Cases from CSV"
 * feature. Columns match the standard Zephyr Scale import mapping.
 *
 * @param {object[]} tests — array of test objects
 * @returns {string} CSV content ready for Zephyr Scale import
 */
export function buildZephyrCsv(tests) {
  function esc(v) { return `"${String(v ?? "").replace(/"/g, '""')}"`; }

  const headers = [
    "Name", "Objective", "Precondition", "Folder",
    "Status", "Priority", "Component", "Labels",
    "Test Script (Step-by-Step) - Step", "Test Script (Step-by-Step) - Test Data",
    "Test Script (Step-by-Step) - Expected Result",
    "Issue Links",
  ];

  const rows = [];
  for (const t of tests) {
    const steps = t.steps || [];
    const priorityMap = { high: "High", medium: "Normal", low: "Low" };
    const labels = [
      t.type || "functional",
      t.scenario || "positive",
      ...(t.tags || []),
      ...(t.isJourneyTest ? ["journey"] : []),
    ].join(" ");
    const folder = t.type
      ? `/${t.type.charAt(0).toUpperCase() + t.type.slice(1)}`
      : "/Functional";
    const status = t.reviewStatus === "approved" ? "Approved" : "Draft";

    if (steps.length === 0) {
      // Single row with no steps
      rows.push([
        esc(t.name),
        esc(t.description || ""),
        esc(t.preconditions || ""),
        esc(folder),
        esc(status),
        esc(priorityMap[t.priority] || "Normal"),
        esc(""),
        esc(labels),
        esc(""),
        esc(""),
        esc(""),
        esc(t.linkedIssueKey || ""),
      ].join(","));
    } else {
      // One row per step — Zephyr maps multiple rows with the same Name as one test case
      steps.forEach((step, idx) => {
        rows.push([
          esc(idx === 0 ? t.name : ""),
          esc(idx === 0 ? (t.description || "") : ""),
          esc(idx === 0 ? (t.preconditions || "") : ""),
          esc(idx === 0 ? folder : ""),
          esc(idx === 0 ? status : ""),
          esc(idx === 0 ? (priorityMap[t.priority] || "Normal") : ""),
          esc(""),
          esc(idx === 0 ? labels : ""),
          esc(step),
          esc(t.testData && idx === 0 ? JSON.stringify(t.testData) : ""),
          esc(idx === steps.length - 1 ? "Test completes successfully" : ""),
          esc(idx === 0 ? (t.linkedIssueKey || "") : ""),
        ].join(","));
      });
    }
  }

  return [headers.map(esc).join(","), ...rows].join("\n");
}

// ── TestRail CSV ─────────────────────────────────────────────────────────────
// TestRail bulk import expects a specific CSV format.
// See: https://www.gurock.com/testrail/docs/user-guide/howto/import-csv

/**
 * buildTestRailCsv(tests) → string (CSV)
 *
 * @param {object[]} tests
 * @returns {string} CSV content ready for TestRail import
 */
export function buildTestRailCsv(tests) {
  function esc(v) { return `"${String(v ?? "").replace(/"/g, '""')}"`; }

  const headers = ["Title", "Section", "Type", "Priority", "Preconditions", "Steps", "Expected Result", "References"];
  const rows = tests.map(t => {
    const steps = (t.steps || []).map((s, i) => `${i + 1}. ${s}`).join("\n");
    const expectedResult = t.steps?.length > 0 ? t.steps[t.steps.length - 1] : "";
    return [
      esc(t.name),
      esc(t.type || "Functional"),
      esc(t.isJourneyTest ? "End-to-End" : "Functional"),
      esc(t.priority === "high" ? "Critical" : t.priority === "low" ? "Low" : "Medium"),
      esc(t.preconditions || ""),
      esc(steps),
      esc(expectedResult),
      esc(t.linkedIssueKey || ""),
    ].join(",");
  });

  return [headers.map(esc).join(","), ...rows].join("\n");
}