/**
 * Unit tests for batch dashboard display logic.
 *
 * Tests the effectiveStatus() and progress calculation functions that
 * determine how batch status badges and progress bars are rendered in
 * BatchListTab.tsx and BatchDetailModal.tsx.
 *
 * These functions are pure and depend on no external modules, so they
 * are duplicated here to allow isolated testing without React/jsdom.
 */

import { describe, it } from "node:test";
import assert from "node:assert/strict";

// ── Pure functions mirroring BatchListTab.tsx / BatchDetailModal.tsx ──────

/**
 * Returns a composite status key that reflects whether partial failures
 * occurred within a batch. Mirrors effectiveStatus() in the UI components.
 */
function effectiveStatus(batch) {
  const hasFailed = (batch.requestCountsFailed ?? 0) > 0;
  if (!hasFailed) return batch.status;
  const map = {
    completed: "completed_with_failures",
    in_progress: "in_progress_with_failures",
    finalizing: "finalizing_with_failures",
    cancelled: "cancelled_with_failures",
  };
  return map[batch.status] ?? batch.status;
}

/**
 * Computes progress bar segment percentages (green = done, red = failed).
 * Mirrors the inline calculations in BatchListTab and BatchDetailModal.
 */
function progressPcts(batch) {
  const total = batch.requestCountsTotal || 0;
  const completed = batch.requestCountsCompleted || 0;
  const failed = batch.requestCountsFailed || 0;
  const donePct = total > 0 ? (completed / total) * 100 : 0;
  const failedPct = total > 0 ? (failed / total) * 100 : 0;
  return { donePct, failedPct, total, completed, failed };
}

// ── effectiveStatus tests ─────────────────────────────────────────────────

describe("effectiveStatus — no failures", () => {
  it("returns 'completed' when requestCountsFailed is 0", () => {
    assert.equal(effectiveStatus({ status: "completed", requestCountsFailed: 0 }), "completed");
  });

  it("returns 'in_progress' when requestCountsFailed is 0", () => {
    assert.equal(effectiveStatus({ status: "in_progress", requestCountsFailed: 0 }), "in_progress");
  });

  it("returns 'finalizing' when requestCountsFailed is 0", () => {
    assert.equal(effectiveStatus({ status: "finalizing", requestCountsFailed: 0 }), "finalizing");
  });

  it("returns 'cancelled' when requestCountsFailed is 0", () => {
    assert.equal(effectiveStatus({ status: "cancelled", requestCountsFailed: 0 }), "cancelled");
  });

  it("returns 'failed' unchanged (already a failure state)", () => {
    assert.equal(effectiveStatus({ status: "failed", requestCountsFailed: 0 }), "failed");
  });

  it("returns 'validating' unchanged", () => {
    assert.equal(effectiveStatus({ status: "validating", requestCountsFailed: 0 }), "validating");
  });

  it("returns 'expired' unchanged", () => {
    assert.equal(effectiveStatus({ status: "expired", requestCountsFailed: 0 }), "expired");
  });

  it("returns 'cancelling' unchanged", () => {
    assert.equal(effectiveStatus({ status: "cancelling", requestCountsFailed: 0 }), "cancelling");
  });
});

describe("effectiveStatus — with failures", () => {
  it("completed + failures → completed_with_failures", () => {
    assert.equal(
      effectiveStatus({ status: "completed", requestCountsFailed: 3 }),
      "completed_with_failures"
    );
  });

  it("in_progress + failures → in_progress_with_failures", () => {
    assert.equal(
      effectiveStatus({ status: "in_progress", requestCountsFailed: 1 }),
      "in_progress_with_failures"
    );
  });

  it("finalizing + failures → finalizing_with_failures", () => {
    assert.equal(
      effectiveStatus({ status: "finalizing", requestCountsFailed: 2 }),
      "finalizing_with_failures"
    );
  });

  it("cancelled + failures → cancelled_with_failures", () => {
    assert.equal(
      effectiveStatus({ status: "cancelled", requestCountsFailed: 5 }),
      "cancelled_with_failures"
    );
  });

  it("failed + failures → failed (already a terminal error, no extra suffix)", () => {
    // 'failed' means the whole batch failed, not partial — no mapping needed
    assert.equal(effectiveStatus({ status: "failed", requestCountsFailed: 10 }), "failed");
  });

  it("expired + failures → expired (no mapping defined)", () => {
    assert.equal(effectiveStatus({ status: "expired", requestCountsFailed: 1 }), "expired");
  });

  it("validating + failures → validating (no mapping defined)", () => {
    assert.equal(effectiveStatus({ status: "validating", requestCountsFailed: 1 }), "validating");
  });

  it("cancelling + failures → cancelling (no mapping defined)", () => {
    assert.equal(effectiveStatus({ status: "cancelling", requestCountsFailed: 2 }), "cancelling");
  });
});

describe("effectiveStatus — edge cases", () => {
  it("treats null requestCountsFailed as 0", () => {
    assert.equal(effectiveStatus({ status: "completed", requestCountsFailed: null }), "completed");
  });

  it("treats undefined requestCountsFailed as 0", () => {
    assert.equal(effectiveStatus({ status: "completed" }), "completed");
  });

  it("treats negative failed count as 0 (> 0 check is false for negatives)", () => {
    // Negative counts should not happen in practice.
    // The check is `> 0`, so -1 does not trigger the failure mapping.
    assert.equal(effectiveStatus({ status: "completed", requestCountsFailed: -1 }), "completed");
  });
});

// ── Progress percentage tests ─────────────────────────────────────────────

describe("progressPcts — zero total", () => {
  it("returns 0 for both pcts when total is 0", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 0,
      requestCountsCompleted: 0,
      requestCountsFailed: 0,
    });
    assert.equal(donePct, 0);
    assert.equal(failedPct, 0);
  });

  it("returns 0 for both pcts when total is missing", () => {
    const { donePct, failedPct } = progressPcts({});
    assert.equal(donePct, 0);
    assert.equal(failedPct, 0);
  });
});

describe("progressPcts — normal cases", () => {
  it("all completed, no failures → donePct=100, failedPct=0", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 10,
      requestCountsCompleted: 10,
      requestCountsFailed: 0,
    });
    assert.equal(donePct, 100);
    assert.equal(failedPct, 0);
  });

  it("all failed, none completed → donePct=0, failedPct=100", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 4,
      requestCountsCompleted: 0,
      requestCountsFailed: 4,
    });
    assert.equal(donePct, 0);
    assert.equal(failedPct, 100);
  });

  it("mixed: 6 done, 2 failed of 10 total", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 10,
      requestCountsCompleted: 6,
      requestCountsFailed: 2,
    });
    assert.equal(donePct, 60);
    assert.equal(failedPct, 20);
  });

  it("done + failed < total (still in progress)", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 100,
      requestCountsCompleted: 30,
      requestCountsFailed: 10,
    });
    assert.equal(donePct, 30);
    assert.equal(failedPct, 10);
  });

  it("single item done", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 1,
      requestCountsCompleted: 1,
      requestCountsFailed: 0,
    });
    assert.equal(donePct, 100);
    assert.equal(failedPct, 0);
  });

  it("single item failed", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 1,
      requestCountsCompleted: 0,
      requestCountsFailed: 1,
    });
    assert.equal(donePct, 0);
    assert.equal(failedPct, 100);
  });
});

describe("progressPcts — combined progress bar width", () => {
  it("combined pct (done + failed) equals overall processed fraction", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 10,
      requestCountsCompleted: 3,
      requestCountsFailed: 4,
    });
    const combinedPct = Math.round(donePct + failedPct);
    assert.equal(combinedPct, 70); // (3+4)/10 = 70%
  });

  it("combined pct stays ≤ 100 when all processed", () => {
    const { donePct, failedPct } = progressPcts({
      requestCountsTotal: 5,
      requestCountsCompleted: 3,
      requestCountsFailed: 2,
    });
    const combinedPct = donePct + failedPct;
    assert.ok(combinedPct <= 100, `Combined pct ${combinedPct} should not exceed 100`);
    assert.equal(combinedPct, 100);
  });
});
