<script lang="ts">
	import { resolve } from "$app/paths";
	import BookMarked from "$icon/book-marked";
	import ChevronDown from "$icon/chevron-down";
	import ChevronUp from "$icon/chevron-up";
	import File from "$icon/file";
	import { LANGUAGE_COLORS, LANGUAGE_COLOR_FALLBACK } from "$lib/components/repo/language-colors";
	import { chunkLines, matchCount } from "./chunks";
	import type { Chunk, CodeResult } from "./types";

	// rest of the chunks go behind a "show more" disclosure
	const VISIBLE_CHUNKS = 3;

	let { result }: { result: CodeResult } = $props();

	const base = $derived(`/${result.ownerHandle}/${result.repoName}`);
	const filePath = $derived(`${base}/blob/${encodeURIComponent(result.ref)}/${result.path}`);
	const repoHref = $derived(resolve(base as "/"));
	const fileHref = $derived(resolve(filePath as "/"));
	const lineHref = (num: number) => resolve(`${filePath}#L${num}` as "/");

	const visible = $derived(result.chunks.slice(0, VISIBLE_CHUNKS));
	const hidden = $derived(result.chunks.slice(VISIBLE_CHUNKS));
	const hiddenMatches = $derived(matchCount(hidden));
	const dotColor = $derived(
		result.language ? (LANGUAGE_COLORS[result.language] ?? LANGUAGE_COLOR_FALLBACK) : undefined
	);
</script>

{#snippet gap()}
	<div class="bg-background-subtle text-center">
		<span class="text-sm text-foreground-subtle select-none">···</span>
	</div>
{/snippet}

{#snippet body(chunk: Chunk)}
	<div class="overflow-x-auto font-mono text-sm">
		{#each chunkLines(chunk) as line (line.num)}
			<div
				class="flex w-max min-w-full gap-3 px-3 {line.highlight
					? 'bg-background-highlight/30'
					: ''}"
			>
				<a
					href={lineHref(line.num)}
					class="block min-w-10 shrink-0 text-right text-foreground-disabled no-underline select-none hover:text-foreground-subtle hover:underline"
					>{line.num}</a
				>
				<!-- prettier-ignore -->
				<div class="whitespace-pre text-foreground-muted"
					>{#each line.spans as span, i (i)}{#if span.match}<span class="rounded-sm bg-background-highlight/70">{span.text}</span>{:else}{span.text}{/if}{:else}&ZeroWidthSpace;{/each}</div
				>
			</div>
		{/each}
	</div>
{/snippet}

<div
	class="flex flex-col gap-2 rounded border border-border-default bg-background-default p-3 text-foreground-default"
>
	<div class="flex min-w-0 items-center gap-1.5 px-1 font-medium">
		<BookMarked class="size-4 shrink-0 text-foreground-subtle" aria-hidden="true" />
		<a href={repoHref} class="min-w-0 truncate text-foreground-default no-underline hover:underline"
			>{result.ownerHandle}/{result.repoName}</a
		>
	</div>

	<div class="divide-y divide-border-default rounded-sm border border-border-default">
		<div class="flex items-center justify-between gap-3 px-3.5 py-2 text-sm">
			<div class="flex min-w-0 items-center gap-2">
				<File class="size-4 shrink-0 text-foreground-subtle" aria-hidden="true" />
				<a href={fileHref} class="min-w-0 truncate font-mono no-underline hover:underline"
					>{result.path}</a
				>
			</div>
			{#if result.language}
				<div class="flex shrink-0 items-center gap-2 text-foreground-muted">
					<span
						class="inline-block size-2.5 shrink-0 rounded-full"
						style={`background-color: ${dotColor}`}
					></span>
					<span>{result.language}</span>
				</div>
			{/if}
		</div>

		{#each visible as chunk, i (chunk.lineStart)}
			{#if i > 0}{@render gap()}{/if}
			{@render body(chunk)}
		{/each}

		{#if hidden.length > 0}
			<details class="group flex flex-col divide-y divide-border-default">
				<summary
					class="cursor-pointer list-none bg-background-subtle px-1 py-0.5 text-foreground-subtle group-open:order-last group-open:border-t group-open:border-border-default"
				>
					<div class="flex group-open:hidden">
						<ChevronDown class="m-1 size-3" aria-hidden="true" />
						<span class="text-sm select-none"
							>Show {hiddenMatches} more {hiddenMatches === 1 ? "match" : "matches"}</span
						>
					</div>
					<div class="hidden group-open:flex">
						<ChevronUp class="m-1 size-3" aria-hidden="true" />
						<span class="text-sm select-none">Show less</span>
					</div>
				</summary>
				{#each hidden as chunk (chunk.lineStart)}
					{@render gap()}
					{@render body(chunk)}
				{/each}
			</details>
		{/if}
	</div>
</div>
