<script module lang="ts">
	import { defineMeta, type StoryContext } from "@storybook/addon-svelte-csf";
	import { expect, waitFor } from "storybook/test";
	import type { RepoBlobView } from "$lib/api/blob";
	import BlobView from "./BlobView.svelte";

	const lastCommit = {
		hash: "0123456789abcdef0123456789abcdef01234567",
		shortHash: "01234567",
		subject: "add the blob view",
		body: "",
		authorName: "dawn",
		authorEmail: "dawn@example.test",
		when: "2026-07-28T09:00:00Z"
	};

	const codeBlob: RepoBlobView = {
		ref: "main",
		path: "web/src/main.ts",
		kind: "code",
		sizeLabel: "1.2 kB",
		lines: 3,
		contents: 'import { serve } from "./server";\n\nserve({ port: 5555 });\n',
		renderedHtml: null,
		fileTooLarge: false,
		defaultView: "code",
		submodule: null,
		lastCommit
	};

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

	// pierre renders inside a shadow root, findByText cannot see the code
	const shadowText = (canvasElement: HTMLElement) =>
		canvasElement.querySelector("diffs-container")?.shadowRoot?.textContent ?? "";

	const showsCode = async ({ canvas, canvasElement }: PlayContext) => {
		await expect(canvas.getByText("main.ts")).toBeVisible();
		await expect(canvas.getByText("3 lines")).toBeVisible();
		await expect(canvas.getByRole("link", { name: "main" })).toBeVisible();
		await expect(canvas.getByText("TypeScript")).toBeVisible();
		await expect(canvas.getByRole("link", { name: "View raw" })).toBeVisible();
		await waitFor(() => expect(shadowText(canvasElement)).toContain("serve({ port: 5555 })"));
	};

	const { Story } = defineMeta({
		title: "Repo/BlobView",
		component: BlobView,
		tags: ["autodocs"],
		args: { ownerHandle: "dawn", repoName: "tangled", blob: codeBlob, language: "TypeScript" }
	});
</script>

<Story name="Code file" play={showsCode} />

<Story
	name="Markdown rendered"
	args={{
		blob: {
			...codeBlob,
			path: "docs/guide.md",
			kind: "markup",
			lines: 5,
			contents: "# tangled\n\nsocial code collaboration for the at protocol.\n",
			renderedHtml: "<h1>tangled</h1><p>social code collaboration for the at protocol.</p>",
			defaultView: "rendered"
		}
	}}
	play={async ({ canvas, canvasElement, userEvent }: PlayContext) => {
		await expect(canvas.getByRole("heading", { name: "tangled" })).toBeVisible();
		await userEvent.click(canvas.getByRole("button", { name: "View code" }));
		await waitFor(() => expect(shadowText(canvasElement)).toContain("# tangled"));
	}}
/>

<Story
	name="Image"
	args={{
		blob: {
			...codeBlob,
			path: "assets/logo.png",
			kind: "image",
			sizeLabel: "18 kB",
			lines: null,
			contents: null
		}
	}}
	play={async ({ canvas }: PlayContext) => {
		const image = canvas.getByRole("img", { name: "assets/logo.png" });
		await expect(image).toHaveAttribute("src", "/dawn/tangled/raw/main/assets/logo.png");
	}}
/>

<Story
	name="Binary unsupported"
	args={{
		blob: {
			...codeBlob,
			path: "assets/data.bin",
			kind: "other",
			lines: null,
			contents: null
		}
	}}
	play={async ({ canvas }: PlayContext) => {
		await expect(canvas.getByText("Previews are not supported for this file type.")).toBeVisible();
	}}
/>

<Story
	name="Submodule"
	args={{
		blob: {
			...codeBlob,
			path: "vendor/spindle",
			kind: "submodule",
			sizeLabel: null,
			lines: null,
			contents: null,
			submodule: { name: "spindle", url: "https://tangled.org/dawn/spindle" }
		}
	}}
	play={async ({ canvas }: PlayContext) => {
		const link = canvas.getByRole("link", { name: "https://tangled.org/dawn/spindle" });
		await expect(link).toBeVisible();
		await expect(canvas.getByText(/This directory is a git submodule of/)).toBeVisible();
	}}
/>

<Story
	name="File too large"
	args={{
		blob: {
			...codeBlob,
			path: "data/dump.sql",
			sizeLabel: "3.4 MB",
			lines: null,
			contents: null,
			fileTooLarge: true
		}
	}}
	play={async ({ canvas }: PlayContext) => {
		await expect(canvas.getByText(/This file is too large to render/)).toBeVisible();
		await expect(canvas.getByRole("link", { name: "View raw." })).toHaveAttribute(
			"href",
			"/dawn/tangled/raw/main/data/dump.sql"
		);
	}}
/>
