<script module lang="ts">
	import { tv, type VariantProps } from "tailwind-variants";

	export const topbar = tv({
		slots: {
			nav: "h-11.5 w-full px-5",
			row: "flex h-full items-center justify-between gap-4",
			brand: "flex shrink-0 items-center gap-2",
			logo: "flex shrink-0 items-center gap-2 no-underline hover:no-underline",
			wordmark: "hidden sm:inline-flex",
			mark: "inline-flex sm:hidden",
			actions: "flex items-center",
			action: "flex items-center",
			divider: "mx-2 hidden h-6 w-px self-center rounded-md bg-background-inset md:block",
			link: "flex items-center text-foreground-default transition-colors hover:text-foreground-muted",
			identity: "flex items-center",
			ball: "size-8 rounded-full bg-background-inset md:size-5",
			bar: "hidden h-4 w-24 rounded-sm bg-background-inset md:block"
		},
		variants: {
			variant: {
				marketing: { actions: "gap-3.5" },
				app: {
					nav: "border-b border-border-default bg-background-default",
					actions: "gap-2"
				}
			},
			// The signing-in placeholder wraps a spinner, so its ball gets a border and tighter gap.
			pending: {
				true: {
					identity: "gap-1",
					ball: "flex items-center justify-center border border-border-default text-foreground-placeholder"
				},
				false: { identity: "gap-2" }
			}
		},
		defaultVariants: {
			pending: false
		}
	});

	export type TopbarVariants = VariantProps<typeof topbar>;
</script>

<script lang="ts">
	import { resolve } from "$app/paths";
	import Button from "../ui/Button.svelte";
	import Dropdown from "../ui/Dropdown.svelte";
	import DropdownItem from "../ui/DropdownItem.svelte";
	import ArrowRight from "$icon/arrow-right";
	import Bell from "$icon/bell";
	import BookMarked from "$icon/book-marked";
	import BookPlus from "$icon/book-plus";
	import Cog from "$icon/cog";
	import LineSquiggle from "$icon/line-squiggle";
	import LogOut from "$icon/log-out";
	import Plus from "$icon/plus";
	import Search from "$icon/search";
	import UserIcon from "$icon/user";
	import Spinner from "../ui/Spinner.svelte";
	import Logo from "../ui/Logo.svelte";
	import User from "../ui/User.svelte";
	import TopbarSearch from "./TopbarSearch.svelte";
	import type { CurrentUser } from "$lib/auth.svelte";
	import Separator from "../ui/Separator.svelte";

	interface Props {
		variant: NonNullable<TopbarVariants["variant"]>;
		onSignOut?: () => void | Promise<void>;
		user: CurrentUser | null;
		loading?: boolean;
	}

	let { variant, onSignOut, user, loading = false }: Props = $props();

	const appPath = (path: string) => resolve(path as "/");

	const style = $derived(topbar({ variant }));
</script>

<nav class={style.nav()} aria-label="main">
	<div class={style.row()}>
		<div class={style.brand()}>
			<a href={resolve("/")} class={style.logo()}>
				<span class={style.wordmark()}>
					<Logo wordmark alpha class="h-6.5" />
				</span>
				<span class={style.mark()}>
					<img src="/logos/dolly.svg" alt="tangled" class="size-8" />
				</span>
			</a>
		</div>

		<div class={style.actions()}>
			{#if variant === "marketing"}
				<TopbarSearch />

				<div class={style.divider()}></div>

				<Button variant="ghost" href={resolve("/login")}>Login</Button>

				<span class="typography-paragraph-small text-foreground-muted">or</span>

				<Button variant="primary" href={resolve("/signup")} insetShadow={true}>
					<span>Join now</span>
					<ArrowRight class="size-3" aria-hidden="true" />
				</Button>
			{:else}
				{#if user || loading}
					<div class={style.action({ class: "order-3 hidden sm:block md:order-1" })}>
						<TopbarSearch />
					</div>

					<div class={style.action({ class: "order-1 md:order-3" })}>
						<Dropdown
							insetShadow={true}
							size="sm"
							id="new-menu"
							group="topbar"
							variant="button"
							align="right"
						>
							{#snippet trigger()}
								<Plus class="size-3.5" aria-hidden="true" />
								<span class="hidden md:inline">New</span>
							{/snippet}
							<DropdownItem href="/repo/new" icon={BookPlus}>New repository</DropdownItem>
							<DropdownItem href="/strings/new" icon={LineSquiggle}>New string</DropdownItem>
						</Dropdown>
					</div>

					<div class={style.action({ class: "order-2 md:order-4" })}>
						<Button
							variant="ghost"
							href={appPath("/notifications")}
							icon={Bell}
							size="sm"
							aria-hidden="true"
							aria-label="Notifications"
						/>
					</div>

					<div class="order-3 md:hidden">
						<Button
							variant="ghost"
							href={appPath("/search")}
							icon={Search}
							size="sm"
							aria-hidden="true"
							aria-label="Search"
						/>
					</div>

					<div class={style.divider({ class: "md:order-2" })}></div>
				{/if}

				<div class={style.action({ class: "order-4 md:order-5" })}>
					{#if loading}
						<div class={style.identity({ pending: true })} role="status" aria-label="Signing in">
							<span class={style.ball({ pending: true })}>
								<Spinner class="size-4" />
							</span>
							<span class={style.bar()} aria-hidden="true"></span>
						</div>
					{:else if user}
						<Dropdown
							id="profile-menu"
							group="topbar"
							align="right"
							variant="button"
							buttonVariant="ghost"
							size="sm"
						>
							{#snippet trigger()}
								<User did={user.did} handle={user.handle} />
							{/snippet}
							<DropdownItem href={`/${user.handle}`} icon={UserIcon}>Profile</DropdownItem>
							<DropdownItem href={`/${user.handle}?tab=repos`} icon={BookMarked}>
								Repositories
							</DropdownItem>
							<DropdownItem href={`/${user.handle}?tab=strings`} icon={LineSquiggle}>
								Strings
							</DropdownItem>
							<DropdownItem href="/settings" icon={Cog}>Settings</DropdownItem>
							<Separator />
							<DropdownItem danger icon={LogOut} onclick={onSignOut}>Logout</DropdownItem>
						</Dropdown>
					{:else}
						<div class={style.identity()} aria-hidden="true">
							<span class={style.ball()}></span>
							<span class={style.bar()}></span>
						</div>
					{/if}
				</div>
			{/if}
		</div>
	</div>
</nav>
