import { describe, expect, it } from "vitest";
import { chunkLines, matchCount } from "./chunks";

/** compact view of a line: line number + its spans as "plain" / "[match]" */
const shape = (chunk: Parameters<typeof chunkLines>[0]) =>
	chunkLines(chunk).map((l) => [l.num, l.spans.map((s) => (s.match ? `[${s.text}]` : s.text))]);

describe("chunkLines", () => {
	it("numbers lines from lineStart and splits each into plain/matched spans", () => {
		// "main" at bytes 5-9, "main" again at 21-25
		const content = "func main() {\n\tcallMain()\n}\n";
		expect(shape({ content, lineStart: 12, highlights: [{ start: 5, end: 9 }] })).toEqual([
			[12, ["func ", "[main]", "() {"]],
			[13, ["\tcallMain()"]],
			[14, ["}"]]
		]);
	});

	it("clips a highlight that spans a newline to each line it covers", () => {
		// bytes 2-8 cover "c\nde" — "b\n" is at 1-3
		const content = "abc\ndef";
		expect(shape({ content, lineStart: 1, highlights: [{ start: 2, end: 6 }] })).toEqual([
			[1, ["ab", "[c]"]],
			[2, ["[de]", "f"]]
		]);
	});

	it("uses byte offsets, not UTF-16 indices", () => {
		// "héllo wörld": h(1) é(2) l l o space w -> "wörld" starts at byte 7
		const content = "héllo wörld";
		expect(shape({ content, lineStart: 1, highlights: [{ start: 7, end: 13 }] })).toEqual([
			[1, ["héllo ", "[wörld]"]]
		]);
	});

	it("emits an empty span list for a blank line and no spurious trailing line", () => {
		expect(shape({ content: "a\n\nb\n", lineStart: 3 })).toEqual([
			[3, ["a"]],
			[4, []],
			[5, ["b"]]
		]);
	});

	it("merges overlapping and adjacent highlights", () => {
		const content = "abcdef";
		expect(
			shape({
				content,
				lineStart: 1,
				highlights: [
					{ start: 3, end: 5 },
					{ start: 1, end: 3 },
					{ start: 4, end: 6 }
				]
			})
		).toEqual([[1, ["a", "[bcdef]"]]]);
	});
});

describe("matchCount", () => {
	it("sums highlights across chunks, counting a missing list as zero", () => {
		expect(
			matchCount([
				{ content: "a", lineStart: 1, highlights: [{ start: 0, end: 1 }] },
				{ content: "b", lineStart: 2 }
			])
		).toBe(1);
	});
});
