<script lang="ts">
	import { page } from "$app/state";
	import Check from "$icon/check";
	import Copy from "$icon/copy";
	import Download from "$icon/download";
	import Checkbox from "$lib/components/ui/Checkbox.svelte";
	import Dropdown from "$lib/components/ui/Dropdown.svelte";
	import type { RepoInfo } from "./types";

	interface Props {
		repo: RepoInfo;
		ref: string;
		bobbinUrl: string;
	}

	let { repo, ref, bobbinUrl }: Props = $props();

	// ssh for knot1 goes through the main domain, other knots serve their own. the
	// knot field is usually a bare host but a scheme and port are both allowed
	const sshHost = $derived(
		(repo.knot === "knot1.tangled.sh" ? "tangled.org" : repo.knot)
			.replace(/^[a-z]+:\/\//, "")
			.split(/[:/]/)[0]
	);
	const origin = $derived(page.url.origin);

	let permalink = $state(false);
	let copied = $state<string | null>(null);

	const urls = $derived([
		{
			label: "HTTPS",
			handle: `${origin}/${repo.ownerHandle}/${repo.name}`,
			perma: repo.repoDid ? `${origin}/${repo.repoDid}` : null
		},
		{
			label: "SSH",
			handle: `git@${sshHost}:${repo.ownerHandle}/${repo.name}`,
			perma: repo.repoDid ? `git@${sshHost}:${repo.repoDid}` : null
		}
	]);

	const archiveUrl = (format: "tar.gz" | "zip") => {
		const url = new URL("/xrpc/sh.tangled.repo.archive", `${bobbinUrl}/`);
		url.searchParams.set("repo", repo.uri);
		url.searchParams.set("ref", ref);
		url.searchParams.set("format", format);
		return url.toString();
	};

	const copy = async (label: string, value: string) => {
		try {
			await navigator.clipboard.writeText(value);
			copied = label;
			setTimeout(() => (copied = copied === label ? null : copied), 2000);
		} catch {
			// clipboard was denied, the text is still selectable
		}
	};
</script>

<Dropdown
	variant="button"
	buttonVariant="primary"
	align="right"
	label="Clone this repository"
	menuClass="w-96 divide-y-0 p-4"
>
	{#snippet trigger()}
		<Download class="size-4" aria-hidden="true" />
		<span class="hidden md:inline">Code</span>
	{/snippet}

	<div class="flex items-center justify-between">
		<h3 class="text-sm font-medium text-foreground-default">Clone this repository</h3>
		{#if repo.repoDid}
			<Checkbox bind:checked={permalink} class="typography-paragraph-small text-foreground-muted">
				Use permalink
			</Checkbox>
		{/if}
	</div>

	{#each urls as entry (entry.label)}
		{@const value = permalink && entry.perma ? entry.perma : entry.handle}
		<div class="mt-4">
			<span class="mb-1 block typography-paragraph-small font-medium text-foreground-muted"
				>{entry.label}</span
			>
			<div
				class="flex items-stretch divide-x divide-border-default rounded-sm border border-border-default"
			>
				<span
					class="flex-1 overflow-x-auto bg-background-inset px-3 py-2 font-mono text-sm whitespace-nowrap text-foreground-default select-all"
					>{value}</span
				>
				<button
					type="button"
					class="cursor-pointer px-3 py-2 text-foreground-subtle hover:text-foreground-default"
					title="Copy to clipboard"
					aria-label={`Copy ${entry.label} clone url`}
					onclick={() => copy(entry.label, value)}
				>
					{#if copied === entry.label}
						<Check class="size-4" aria-hidden="true" />
					{:else}
						<Copy class="size-4" aria-hidden="true" />
					{/if}
				</button>
			</div>
		</div>
	{/each}

	<p class="mt-2 typography-paragraph-small text-foreground-subtle">
		For self-hosted knots, clone URLs may differ based on your setup.
	</p>

	<!-- archives come from bobbin, so these are external links -->
	<div class="mt-4 flex gap-2">
		{#each [{ format: "tar.gz" }, { format: "zip" }] as const as archive (archive.format)}
			<a
				href={archiveUrl(archive.format)}
				rel="external noopener noreferrer"
				class="flex flex-1 items-center justify-center gap-2 rounded-sm border border-border-default px-2 py-1.5 text-sm text-foreground-default no-underline hover:bg-background-subtle hover:no-underline"
			>
				<Download class="size-4" aria-hidden="true" />
				{archive.format === "zip" ? ".zip" : archive.format}
			</a>
		{/each}
	</div>
</Dropdown>
