import { describe, expect, it } from "vitest";
import {
  formatBytes,
  formatDurationMs,
  formatInt,
  formatPercent,
  formatUtc,
  objectTypeLabel,
  parseTime,
  truncateMiddle,
} from "./format";

describe("formatInt", () => {
  it("formats with thousands separators", () => {
    expect(formatInt(1234567)).toBe("1,234,567");
  });
  it("renders dash for nullish", () => {
    expect(formatInt(null)).toBe("—");
    expect(formatInt(undefined)).toBe("—");
  });
});

describe("formatBytes", () => {
  it("keeps small values in bytes", () => {
    expect(formatBytes(512)).toBe("512 B");
  });
  it("scales to KiB/MiB/GiB", () => {
    expect(formatBytes(2048)).toBe("2.0 KiB");
    expect(formatBytes(5 * 1024 * 1024)).toBe("5.0 MiB");
    expect(formatBytes(3 * 1024 ** 3)).toBe("3.0 GiB");
  });
  it("renders dash for nullish", () => {
    expect(formatBytes(null)).toBe("—");
  });
});

describe("formatDurationMs", () => {
  it("sub-second values", () => {
    expect(formatDurationMs(640)).toBe("640 ms");
  });
  it("seconds", () => {
    expect(formatDurationMs(4200)).toBe("4.2s");
    expect(formatDurationMs(42_000)).toBe("42s");
  });
  it("minutes and hours", () => {
    expect(formatDurationMs(3 * 60_000 + 4_000)).toBe("3m 04s");
    expect(formatDurationMs(2 * 3_600_000 + 5 * 60_000)).toBe("2h 05m");
  });
});

describe("parseTime / formatUtc", () => {
  it("parses RFC3339 and renders UTC", () => {
    expect(formatUtc("2026-07-17T01:46:55Z")).toBe("2026-07-17 01:46:55 UTC");
  });
  it("passes through unparseable input", () => {
    expect(formatUtc("not-a-date")).toBe("not-a-date");
    expect(parseTime("not-a-date")).toBeNull();
  });
  it("renders dash for missing values", () => {
    expect(formatUtc(null)).toBe("—");
    expect(formatUtc(undefined)).toBe("—");
  });
});

describe("formatPercent", () => {
  it("computes one decimal", () => {
    expect(formatPercent(1, 3)).toBe("33.3%");
  });
  it("guards zero total", () => {
    expect(formatPercent(1, 0)).toBe("—");
  });
  it("marks tiny non-zero shares instead of rounding to 0.0%", () => {
    expect(formatPercent(1, 5000)).toBe("<0.1%");
    expect(formatPercent(0, 5000)).toBe("0.0%");
  });
  it("marks near-complete shares instead of rounding to 100.0%", () => {
    expect(formatPercent(4999, 5000)).toBe(">99.9%");
    expect(formatPercent(5000, 5000)).toBe("100.0%");
  });
});

describe("truncateMiddle", () => {
  it("keeps short values intact", () => {
    expect(truncateMiddle("abc", 10)).toBe("abc");
  });
  it("truncates with an ellipsis keeping head and tail", () => {
    const out = truncateMiddle("a".repeat(100), 21);
    expect(out.length).toBe(21);
    expect(out).toContain("…");
    expect(out.startsWith("a".repeat(10))).toBe(true);
    expect(out.endsWith("a".repeat(10))).toBe(true);
  });
});

describe("objectTypeLabel", () => {
  it("maps known types", () => {
    expect(objectTypeLabel("roa")).toBe("ROA");
    expect(objectTypeLabel("mft")).toBe("Manifest");
    expect(objectTypeLabel("asa")).toBe("ASPA");
  });
  it("maps router certificate spellings", () => {
    expect(objectTypeLabel("router_certificate")).toBe("Router certificate");
    expect(objectTypeLabel("router_cert")).toBe("Router certificate");
  });
  it("uppercases unknown types", () => {
    expect(objectTypeLabel("xyz")).toBe("XYZ");
  });
  it("renders dash for missing", () => {
    expect(objectTypeLabel(null)).toBe("—");
  });
});
