/**
 * Ticket #54 F2 — pure download-progress formatting for the model-server overlay.
 * These lock the wire→display mapping independently of React: byte formatting,
 * the determinate/indeterminate split, and the "no fake %" rule.
 */
import { describe, it, expect } from "vitest";

import type { ModelServerStatus } from "@/domain";
import {
  formatBytes,
  describeModelServerDownload,
  modelServerOverlayText,
} from "./modelServerLaunch";

function downloading(
  fields: Partial<{
    downloadedBytes: number | null;
    totalBytes: number | null;
    percent: number | null;
    source: string | null;
  }> = {},
): ModelServerStatus {
  return {
    state: "downloading",
    downloadedBytes: null,
    totalBytes: null,
    percent: null,
    source: null,
    ...fields,
  };
}

describe("formatBytes", () => {
  it("shows whole bytes and SI-scaled larger units", () => {
    expect(formatBytes(0)).toBe("0 o");
    expect(formatBytes(512)).toBe("512 o");
    expect(formatBytes(1000)).toBe("1 Ko");
    expect(formatBytes(1_500_000)).toBe("1.5 Mo");
    expect(formatBytes(4_200_000_000)).toBe("4.2 Go");
  });

  it("guards non-finite / negative", () => {
    expect(formatBytes(-5)).toBe("0 o");
    expect(formatBytes(Number.NaN)).toBe("0 o");
  });
});

describe("describeModelServerDownload", () => {
  it("returns null for every non-downloading state", () => {
    expect(describeModelServerDownload(undefined)).toBeNull();
    expect(describeModelServerDownload({ state: "probing" })).toBeNull();
    expect(describeModelServerDownload({ state: "starting" })).toBeNull();
    expect(
      describeModelServerDownload({ state: "ready", reused: false }),
    ).toBeNull();
  });

  it("exposes percent + a 'X / Y' bytes label when both bounds are known", () => {
    const p = describeModelServerDownload(
      downloading({
        downloadedBytes: 1_500_000,
        totalBytes: 3_000_000,
        percent: 50,
        source: "unsloth/Qwen3-Coder-30B",
      }),
    );
    expect(p).toEqual({
      percent: 50,
      bytesLabel: "1.5 Mo / 3 Mo",
      source: "unsloth/Qwen3-Coder-30B",
    });
  });

  it("clamps percent to 0..100", () => {
    expect(describeModelServerDownload(downloading({ percent: 137 }))?.percent).toBe(
      100,
    );
    expect(describeModelServerDownload(downloading({ percent: -3 }))?.percent).toBe(
      0,
    );
  });

  it("is indeterminate (percent null) when the total is unknown", () => {
    const p = describeModelServerDownload(
      downloading({ downloadedBytes: 800_000, totalBytes: null, percent: null }),
    );
    expect(p).toEqual({ percent: null, bytesLabel: "800 Ko", source: null });
  });

  it("has no bytes label when nothing about size is known", () => {
    expect(describeModelServerDownload(downloading())).toEqual({
      percent: null,
      bytesLabel: null,
      source: null,
    });
  });
});

describe("modelServerOverlayText (unchanged F1 titles)", () => {
  it("keeps the download / loading titles", () => {
    expect(modelServerOverlayText(downloading())).toBe(
      "Téléchargement du modèle…",
    );
    expect(modelServerOverlayText({ state: "starting" })).toBe(
      "Chargement du serveur…",
    );
    expect(modelServerOverlayText({ state: "ready", reused: true })).toBeNull();
  });
});
