import { describe, it, expect } from "vitest";
import { fatalNetworkErrorAction } from "./hlsRecovery";

/**
 * A fatal hls.js network error mid-film must be retried, not reported as the
 * end of the stream — reporting "ended" hands control to autoplay and skips to
 * the next item while the user is still watching this one.
 *
 * The position the player displays is *already absolute*: the RAF loop sets
 * `currentTime = seekOffset + element.currentTime`. Anything that adds the
 * offset a second time doubles the apparent position, and after a quality
 * switch or a transcoded seek the offset is the whole resume position — so past
 * roughly the halfway mark the doubled value clears the near-end threshold and
 * every transient error is misread as the end.
 *
 * TRACES: UR-004, UR-074 | DR-177 | UT-174
 */
describe("fatalNetworkErrorAction", () => {
  it("retries a mid-film failure after a quality switch instead of ending playback", () => {
    // 90-minute film, quality switched at the 50-minute mark: the reloaded
    // stream's timeline starts at 0, so seekOffset carries the 50 minutes and
    // the displayed position — already absolute — is 3000s of 5400s, 56%
    // through and nowhere near the end.
    const action = fatalNetworkErrorAction({
      positionSeconds: 3000,
      knownDurationSeconds: 5400,
      attempts: 1,
    });

    expect(action).toBe("retry");
  });

  it("treats a failure in the last tenth of the stream as the end", () => {
    // Jellyfin's transcoded HLS does not always emit #EXT-X-ENDLIST, so a
    // genuine end-of-stream arrives as a fatal network error.
    const action = fatalNetworkErrorAction({
      positionSeconds: 5300,
      knownDurationSeconds: 5400,
      attempts: 1,
    });

    expect(action).toBe("ended");
  });

  it("stops retrying once the recovery budget is spent", () => {
    const action = fatalNetworkErrorAction({
      positionSeconds: 60,
      knownDurationSeconds: 5400,
      attempts: 4,
    });

    expect(action).toBe("giveUp");
  });

  it("retries when the runtime is not known yet", () => {
    const action = fatalNetworkErrorAction({
      positionSeconds: 120,
      knownDurationSeconds: 0,
      attempts: 1,
    });

    expect(action).toBe("retry");
  });
});
