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

	// the sizes the design system names, from Figma's User component (node 723:254).
	// Size=Header is not a rung here: it draws the same 26px circle as Size=Large
	// and differs only in the text style beside it.
	export const avatar = tv({
		base: "shrink-0 rounded-full border border-border-default",
		variants: {
			size: {
				mini: "size-3.25",
				small: "size-4.25",
				regular: "size-5.25",
				large: "size-6.5",
				// for a size off the scale: `full` fills the parent, and a size class
				// passed by the caller replaces it, since tv() merges the two rather
				// than leaving both to fight in the class string
				full: "size-full"
			}
		},
		defaultVariants: {
			size: "regular"
		}
	});

	export type AvatarSize = NonNullable<VariantProps<typeof avatar>["size"]>;

	// what each rung above renders at, in css pixels — the spacing unit is 4px, so
	// these are the class numbers times four. the avatar is fetched at twice this so
	// that it stays sharp at 2x. `full` has no size of its own, the layout decides
	// it, so there is nothing to fetch at.
	const sizePx = {
		mini: 13,
		small: 17,
		regular: 21,
		large: 26,
		full: undefined
	} satisfies Record<AvatarSize, number | undefined>;

	export const avatarSizeNames = Object.keys(sizePx) as AvatarSize[];
</script>

<script lang="ts">
	import UserRound from "$icon/user-round";
	import { avatarUrl } from "$lib/avatar";

	interface Props {
		did?: string;
		src?: string;
		handle?: string;
		size?: AvatarSize;
		class?: string;
	}

	let { did, src, handle, size = "regular", class: className = "" }: Props = $props();

	const px = $derived(sizePx[size]);
	const source = $derived(
		src ?? (did ? avatarUrl(did, px === undefined ? undefined : px * 2) : undefined)
	);

	// an unconfigured avatar service 404s, same as a broken image
	let failed = $state(false);

	$effect(() => {
		if (source) failed = false;
	});
</script>

{#if source && !failed}
	<img
		src={source}
		alt={handle ? `${handle}'s avatar` : "avatar"}
		class={avatar({ size, class: `object-cover ${className}` })}
		onerror={() => (failed = true)}
	/>
{:else}
	<span
		class={avatar({
			size,
			class: `flex items-center justify-center bg-background-canvas text-foreground-subtle ${className}`
		})}
		role={handle ? "img" : undefined}
		aria-label={handle ? `${handle}'s avatar` : undefined}
		aria-hidden={handle ? undefined : "true"}
	>
		<UserRound class="size-1/2" />
	</span>
{/if}
