<script module lang="ts">
	import { defineMeta, type StoryContext } from "@storybook/addon-svelte-csf";
	import { expect, waitFor } from "storybook/test";
	import type { DiffFile } from "$lib/api/diff";
	import { toFileDiffMetadata } from "./fileDiff";
	import DiffFileCard from "./DiffFileCard.svelte";

	const textFile: DiffFile = {
		name: { old: "src/colors.ts", new: "src/colors.ts" },
		text_fragments: [
			{
				OldPosition: 1,
				OldLines: 3,
				NewPosition: 1,
				NewLines: 4,
				LinesAdded: 2,
				LinesDeleted: 1,
				Lines: [
					{ Op: 0, Line: "export const palette = {\n" },
					{ Op: 1, Line: '\tbackground: "white",\n' },
					{ Op: 2, Line: '\tbackground: "oklch(0.98 0 0)",\n' },
					{ Op: 2, Line: '\tforeground: "oklch(0.2 0 0)",\n' },
					{ Op: 0, Line: "};\n" }
				]
			}
		]
	};

	const renamedFile: DiffFile = {
		name: { old: "src/old-name.ts", new: "src/new-name.ts" },
		text_fragments: [
			{
				OldPosition: 1,
				OldLines: 1,
				NewPosition: 1,
				NewLines: 1,
				LinesAdded: 1,
				LinesDeleted: 1,
				Lines: [
					{ Op: 1, Line: "export const old = true;\n" },
					{ Op: 2, Line: "export const fresh = true;\n" }
				]
			}
		]
	};

	const binaryFile: DiffFile = {
		name: { old: "assets/logo.png", new: "assets/logo.png" },
		is_binary: true
	};

	const diffFor = (file: DiffFile) => toFileDiffMetadata(file);

	// pierre renders inside a shadow root, invisible to canvas queries
	const shadowText = (canvasElement: HTMLElement) =>
		[...canvasElement.querySelectorAll("diffs-container")]
			.map((host) => host.shadowRoot?.textContent ?? "")
			.join("\n");

	type PlayContext = Pick<
		StoryContext<Record<string, unknown>>,
		"canvas" | "canvasElement" | "userEvent"
	>;

	const { Story } = defineMeta({
		title: "Repo/DiffFileCard",
		component: DiffFileCard,
		tags: ["autodocs"],
		args: {
			file: textFile,
			name: "src/colors.ts",
			stat: { insertions: 2, deletions: 1, files_changed: 1 },
			fileDiff: diffFor(textFile)
		}
	});
</script>

<Story
	name="Default"
	play={async ({ canvasElement }: PlayContext) => {
		await waitFor(() => expect(shadowText(canvasElement)).toContain("oklch(0.98 0 0)"));
	}}
/>

<Story
	name="Collapse toggle"
	play={async ({ canvas, canvasElement, userEvent }: PlayContext) => {
		const card = canvasElement.querySelector("details")!;
		await expect(card.open).toBe(true);
		await userEvent.click(card.querySelector("summary")!);
		await expect(card.open).toBe(false);
		await userEvent.click(card.querySelector("summary")!);
		await expect(card.open).toBe(true);
		await expect(canvas.getByText("src/colors.ts")).toBeInTheDocument();
	}}
/>

<Story
	name="Renamed file"
	args={{
		file: renamedFile,
		name: "src/new-name.ts",
		fileDiff: diffFor(renamedFile)
	}}
	play={async ({ canvasElement }: PlayContext) => {
		// both names live in the same flex row, match the joined text
		const header = canvasElement.querySelector("summary")!;
		await expect(header.textContent).toContain("src/old-name.ts");
		await expect(header.textContent).toContain("src/new-name.ts");
	}}
/>

<Story
	name="Binary file"
	args={{
		file: binaryFile,
		name: "assets/logo.png",
		stat: { insertions: 0, deletions: 0, files_changed: 1 },
		fileDiff: undefined
	}}
	play={async ({ canvas }: PlayContext) => {
		await expect(
			canvas.getByText("This is a binary file and will not be displayed.")
		).toBeInTheDocument();
	}}
/>

<Story
	name="View file link"
	args={{ blobUrl: "/dawn/tangled/blob/master/src/colors.ts" }}
	play={async ({ canvas }: PlayContext) => {
		await expect(canvas.getByRole("link", { name: /view file/i })).toHaveAttribute(
			"href",
			"/dawn/tangled/blob/master/src/colors.ts"
		);
	}}
/>
