import { describe, expect, it } from "vitest";
import { getRetryDelayMs, shouldRetry } from "./retry";
import { NetworkError, RateLimitError, TimeoutError } from "../errors/dify-error";

const withMockedRandom = (value: number, fn: () => void): void => {
  const original = Math.random;
  Math.random = () => value;
  try {
    fn();
  } finally {
    Math.random = original;
  }
};

describe("retry helpers", () => {
  it("getRetryDelayMs honors retry-after header", () => {
    expect(getRetryDelayMs(1, 1, 3)).toBe(3000);
  });

  it("getRetryDelayMs uses exponential backoff with jitter", () => {
    withMockedRandom(0, () => {
      expect(getRetryDelayMs(1, 1)).toBe(1000);
      expect(getRetryDelayMs(2, 1)).toBe(2000);
      expect(getRetryDelayMs(3, 1)).toBe(4000);
    });
  });

  it("shouldRetry respects max retries", () => {
    expect(shouldRetry(new TimeoutError("timeout"), 3, 3)).toBe(false);
  });

  it("shouldRetry retries on network, timeout, and rate limit", () => {
    expect(shouldRetry(new TimeoutError("timeout"), 0, 3)).toBe(true);
    expect(shouldRetry(new NetworkError("network"), 0, 3)).toBe(true);
    expect(shouldRetry(new RateLimitError("limit"), 0, 3)).toBe(true);
    expect(shouldRetry(new Error("other"), 0, 3)).toBe(false);
  });
});
