<script lang="ts">
	import { resolve } from "$app/paths";
	import Copy from "$icon/copy";
	import CopyCheck from "$icon/copy-check";
	import Ellipsis from "$icon/ellipsis";
	import FolderCode from "$icon/folder-code";
	import Avatar from "$lib/components/ui/Avatar.svelte";
	import Pagination from "$lib/components/ui/Pagination.svelte";
	import Tag from "$lib/components/ui/Tag.svelte";
	import TimeAgo from "$lib/components/ui/TimeAgo.svelte";
	import { createCopyFeedback } from "$lib/copy.svelte";
	import type { CommitSummary } from "./types";

	interface Props {
		ownerHandle: string;
		repoName: string;
		ref: string;
		commits: CommitSummary[];
		tagsByCommit?: Record<string, string[]>;
		page: number;
		pageCount: number;
		onPageChange?: (page: number) => void;
	}

	let {
		ownerHandle,
		repoName,
		ref,
		commits,
		tagsByCommit = {},
		page,
		pageCount,
		onPageChange
	}: Props = $props();

	const base = $derived(`/${ownerHandle}/${repoName}`);

	let expanded = $state<Record<string, boolean>>({});
	const copyFeedback = createCopyFeedback();
</script>

{#snippet authorCell(commit: CommitSummary)}
	<span class="flex items-center gap-1">
		<!-- no did/handle on a commit summary, always the placeholder -->
		<Avatar size="size-6" />
		{#if commit.authorEmail}
			<a href="mailto:{commit.authorEmail}" class="no-underline hover:underline">
				{commit.authorName}
			</a>
		{:else}
			<span>{commit.authorName}</span>
		{/if}
	</span>
{/snippet}

{#snippet shaChip(commit: CommitSummary, mobile: boolean)}
	<a
		href={resolve(`${base}/commit/${commit.hash}` as "/")}
		title={commit.changeId ? `jj change id: ${commit.changeId}` : undefined}
		class="flex items-center gap-2 rounded bg-background-inset px-2 {mobile
			? 'py-1'
			: 'py-0.5'} text-foreground-muted no-underline hover:underline"
	>
		{commit.shortHash}
	</a>
{/snippet}

{#snippet treeLink(commit: CommitSummary)}
	<a
		href={resolve(`${base}/tree/${commit.hash}` as "/")}
		class="rounded p-1 hover:bg-background-inset"
		title="Browse repository at this commit"
		aria-label="Browse repository at this commit"
	>
		<FolderCode class="size-4" aria-hidden="true" />
	</a>
{/snippet}

{#snippet copyButton(commit: CommitSummary)}
	<button
		type="button"
		class="cursor-pointer rounded p-1 hover:bg-background-inset"
		title="Copy SHA"
		aria-label="Copy SHA"
		onclick={() => void copyFeedback.copy(commit.hash)}
	>
		{#if copyFeedback.copied === commit.hash}
			<CopyCheck class="size-4" aria-hidden="true" />
		{:else}
			<Copy class="size-4" aria-hidden="true" />
		{/if}
	</button>
{/snippet}

{#snippet messageCell(commit: CommitSummary)}
	<div>
		<a
			href={resolve(`${base}/commit/${commit.hash}` as "/")}
			class="text-foreground-default no-underline hover:underline"
		>
			{commit.subject}
		</a>
		{#if commit.body}
			<button
				type="button"
				class="cursor-pointer rounded bg-background-inset px-1 py-0.5 hover:bg-background-muted"
				aria-expanded={expanded[commit.hash] === true}
				aria-label="Toggle commit body"
				onclick={() => (expanded[commit.hash] = !expanded[commit.hash])}
			>
				<Ellipsis class="size-3" aria-hidden="true" />
			</button>
		{/if}
		{#each tagsByCommit[commit.hash] ?? [] as name (name)}
			<Tag color="gray" class="ml-2 font-mono">{name}</Tag>
		{/each}
	</div>
	{#if commit.body && expanded[commit.hash]}
		<p class="mt-1 typography-paragraph-regular whitespace-pre-wrap text-foreground-muted">
			{commit.body}
		</p>
	{/if}
{/snippet}

<section id="commit-table" class="overflow-x-auto rounded bg-background-default px-6 py-4">
	<h2 class="mb-4 typography-paragraph-regular font-bold">Commits</h2>

	{#if commits.length === 0}
		<p class="py-6 text-center text-foreground-subtle">No commits at {ref}.</p>
	{:else}
		<div class="hidden divide-y divide-border-default md:flex md:flex-col">
			<div class="grid grid-cols-14 gap-4">
				<div
					class="col-span-3 py-2 text-left typography-paragraph-regular font-bold text-foreground-muted"
				>
					Author
				</div>
				<div
					class="col-span-3 py-2 text-left typography-paragraph-regular font-bold text-foreground-muted"
				>
					Commit
				</div>
				<div
					class="col-span-6 py-2 text-left typography-paragraph-regular font-bold text-foreground-muted"
				>
					Message
				</div>
				<div
					class="col-span-2 justify-self-end py-2 text-left typography-paragraph-regular font-bold text-foreground-muted"
				>
					Date
				</div>
			</div>
			{#each commits as commit (commit.hash)}
				<div class="grid grid-cols-14 gap-4 py-3">
					<div class="col-span-3 align-top">
						{@render authorCell(commit)}
					</div>
					<div class="col-span-3 flex items-start align-top font-mono">
						{@render shaChip(commit, false)}
						<!-- TODO: unverified rows indent the actions by a verified-shield
							width, but no shield renders yet. drop the ml-6 or render the
							shield once commit verification lands -->
						<div class="ml-6 inline-flex">
							{@render copyButton(commit)}
							{@render treeLink(commit)}
						</div>
					</div>
					<div class="col-span-6 align-top">
						{@render messageCell(commit)}
					</div>
					<div class="col-span-2 justify-self-end align-top text-foreground-muted">
						<TimeAgo value={commit.when} />
					</div>
				</div>
			{/each}
		</div>

		<div class="md:hidden">
			{#each commits as commit, index (commit.hash)}
				<div
					class="relative mb-2 p-2 {index < commits.length - 1
						? 'border-b border-border-default'
						: ''}"
				>
					<div class="flex items-center justify-between">
						<div class="flex-1">
							{@render messageCell(commit)}
						</div>
						{@render treeLink(commit)}
					</div>
					<div
						class="mt-2 flex items-center gap-1 typography-paragraph-small text-foreground-muted"
					>
						<span class="font-mono">
							{@render shaChip(commit, true)}
						</span>
						<span aria-hidden="true">&middot;</span>
						{@render authorCell(commit)}
						{#if commit.when}
							<span aria-hidden="true">&middot;</span>
							<TimeAgo value={commit.when} />
						{/if}
					</div>
				</div>
			{/each}
		</div>
	{/if}
</section>

{#if pageCount > 1}
	<div class="mt-4 flex justify-center">
		<Pagination {page} total={pageCount} labels onchange={onPageChange} class="gap-5" />
	</div>
{/if}
