import { layoutDonut, type DonutSlice } from "./donutLayout";

function slice(key: string, value: number): DonutSlice {
	return { key, label: key, value, color: "#000000" };
}

test("an empty breakdown has no total and no arcs to draw", () => {
	expect(layoutDonut([], 100, 20)).toEqual({ size: 100, total: 0, arcs: [] });
});

test("a breakdown of nothing but zeroes is empty, not a division by zero", () => {
	const layout = layoutDonut([slice("a", 0), slice("b", 0)], 100, 20);
	expect(layout.total).toBe(0);
	expect(layout.arcs).toEqual([]);
});

test("zero-valued entries are dropped rather than legended at 0%", () => {
	const layout = layoutDonut([slice("a", 3), slice("b", 0), slice("c", 1)], 100, 20);
	expect(layout.arcs.map((arc) => arc.slice.key)).toEqual(["a", "c"]);
	expect(layout.total).toBe(4);
});

test("shares are of the drawn total and add up to one", () => {
	const layout = layoutDonut([slice("a", 3), slice("b", 1)], 100, 20);
	expect(layout.arcs.map((arc) => arc.share)).toEqual([0.75, 0.25]);
});

test("slices keep the order they were ranked in, starting at twelve o'clock", () => {
	const layout = layoutDonut([slice("a", 1), slice("b", 1)], 100, 20);
	expect(layout.arcs[0].d.startsWith("M 50.000 0.000")).toBe(true);
	// The second slice begins where the first ended, half a turn round.
	expect(layout.arcs[1].d.startsWith("M 50.000 100.000")).toBe(true);
});

test("a slice over half the ring takes the large-arc flag", () => {
	const layout = layoutDonut([slice("a", 9), slice("b", 1)], 100, 20);
	expect(layout.arcs[0].d).toContain("A 50 50 0 1 1");
	expect(layout.arcs[1].d).toContain("A 50 50 0 0 1");
});

test("a single entry is a closed ring, not a zero-length arc that draws nothing", () => {
	const layout = layoutDonut([slice("only", 7)], 100, 20);
	expect(layout.arcs).toHaveLength(1);
	expect(layout.arcs[0].share).toBe(1);
	// Two half arcs out and two back: a lone `A` from a point to itself is a no-op.
	expect(layout.arcs[0].d.match(/A /g)).toHaveLength(4);
});
