<script lang="ts">
	import ModelCapabilityIcons from './ModelCapabilityIcons.svelte';
	import { Database, ScrollText } from '@lucide/svelte';
	import { TruncatedText } from '$lib/components/app';
	import * as Tooltip from '$lib/components/ui/tooltip';
	import { type ModelSidecar } from '$lib/constants';
	import { HuggingFaceService } from '$lib/services';
	import { ModelsService } from '$lib/services/models.service';
	import { settingsStore } from '$lib/stores';
	import type { ModelModalities } from '$lib/types/models';
	import { isAuxSidecar } from '$lib/utils';
	import { formatParameters } from '$lib/utils';

	interface Props {
		modelId: string;
		hideOrgName?: boolean;
		hideName?: boolean;
		hideModalities?: boolean;
		hideCapabilities?: boolean;
		hideParameters?: boolean;
		showRaw?: boolean;
		showRawTooltip?: boolean;
		hideQuantization?: boolean;
		hideTags?: boolean;
		aliases?: string[];
		tags?: string[];
		/** Render the capability/modality/context icons on a second row. */
		iconsOnNewLine?: boolean;
		modalities?: ModelModalities;
		supportsThinking?: boolean;
		supportsToolUse?: boolean;
		/** Native title for the root element; keeps long lists light where a floating tooltip per row is too costly. */
		title?: string;
		/** Context length in tokens; renders a context icon when set. */
		contextLength?: number;
		/** Min/max GGUF file size (main + draft) across quants; renders a range when set. */
		sizeRange?: { min: number; max: number } | null;
		draftSidecars?: ModelSidecar[];
		/** Allow badges to wrap onto new lines instead of truncating. */
		wrap?: boolean;
		class?: string;
	}

	let {
		aliases,
		class: className = '',
		contextLength,
		draftSidecars = [],
		hideCapabilities = false,
		hideModalities = false,
		hideName = false,
		hideOrgName = false,
		hideParameters = false,
		hideQuantization,
		hideTags,
		iconsOnNewLine = false,
		modalities,
		modelId,
		showRaw = undefined,
		showRawTooltip = false,
		sizeRange,
		supportsThinking = false,
		supportsToolUse = false,
		tags,
		title,
		wrap = false,
		...rest
	}: Props = $props();

	const badgeClass =
		'inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-md border border-border/50 px-1 py-0 text-[10px] font-mono bg-foreground/15 dark:bg-foreground/10 text-foreground [a&]:hover:bg-foreground/25';
	const tagBadgeClass =
		'inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-md border border-border/50 px-1 py-0 text-[10px] font-mono text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground';
	const variantBadgeClass =
		'inline-flex w-fit shrink-0 items-center justify-center whitespace-nowrap rounded-md bg-primary px-1.5 py-0 text-[10px] font-mono font-semibold uppercase tracking-wide text-primary-foreground';

	/** Alias badges beyond this many collapse into a single `+x more` badge. */
	const MAX_ALIAS_BADGES = 2;

	let parsed = $derived(ModelsService.parseModelId(modelId));
	let resolvedShowRaw = $derived(
		showRaw ?? (settingsStore.config.showRawModelNames as boolean) ?? false
	);
	let resolvedHideQuantization = $derived(
		hideQuantization ?? !settingsStore.config.showModelQuantization
	);
	let resolvedHideTags = $derived(hideTags ?? !settingsStore.config.showModelTags);

	let uniqueAliases = $derived([...new Set(aliases ?? [])]);
	let uniqueTags = $derived([...new Set([...(parsed.tags ?? []), ...(tags ?? [])])]);
	let uniqueDraftSidecars = $derived([...new Set(draftSidecars)].filter((s) => !isAuxSidecar(s)));

	let primaryAlias = $derived(uniqueAliases.length === 1 ? uniqueAliases[0] : null);
	let displayName = $derived(primaryAlias ?? parsed.modelName ?? modelId);

	let hasBadges = $derived(
		parsed.sidecar ||
			uniqueDraftSidecars.length > 0 ||
			(parsed.params && !hideParameters) ||
			(parsed.quantization && !resolvedHideQuantization) ||
			primaryAlias ||
			uniqueAliases.length > 1 ||
			(uniqueTags.length > 0 && !resolvedHideTags)
	);
</script>

{#if resolvedShowRaw}
	<TruncatedText class="font-medium {className}" showTooltip={false} text={modelId} {...rest} />
{:else}
	{#snippet nameAndBadges()}
		{#if !hideName}
			<span class="min-w-0 truncate font-medium">
				{#if !hideOrgName && parsed.orgName}{parsed.orgName}/{/if}{displayName}
			</span>
		{/if}

		{#if hasBadges}
			<span class="inline-flex items-center gap-1 {wrap ? 'flex-wrap' : ''}">
				{#if parsed.sidecar}
					<span class={variantBadgeClass} title={`${parsed.sidecar.toUpperCase()} draft model`}>
						{parsed.sidecar}
					</span>
				{/if}

				{#if parsed.params && !hideParameters}
					<span class={badgeClass}>
						{parsed.params}{parsed.activatedParams ? `-${parsed.activatedParams}` : ''}
					</span>
				{/if}

				{#each uniqueDraftSidecars as sidecar (sidecar)}
					<span class={variantBadgeClass} title={`${sidecar.toUpperCase()} draft model available`}>
						{sidecar}
					</span>
				{/each}

				{#if parsed.quantization && !resolvedHideQuantization}
					<span class={badgeClass}>
						{parsed.quantization}
					</span>
				{/if}

				{#if primaryAlias}
					{#if primaryAlias !== parsed.modelName}
						<span class="{badgeClass} max-w-32 truncate" title={parsed.modelName ?? modelId}>
							{parsed.modelName ?? modelId}
						</span>
					{/if}
				{:else if uniqueAliases.length > 1}
					{#each uniqueAliases.slice(0, MAX_ALIAS_BADGES) as alias (alias)}
						<span class="{badgeClass} max-w-32 truncate" title={alias}>
							{alias}
						</span>
					{/each}

					{#if uniqueAliases.length > MAX_ALIAS_BADGES}
						<span class={badgeClass} title={uniqueAliases.slice(MAX_ALIAS_BADGES).join(', ')}>
							+{uniqueAliases.length - MAX_ALIAS_BADGES} more
						</span>
					{/if}
				{/if}

				{#if uniqueTags.length > 0 && !resolvedHideTags}
					{#each uniqueTags as tag (tag)}
						<span class={tagBadgeClass}>{tag}</span>
					{/each}
				{/if}
			</span>
		{/if}
	{/snippet}

	<span
		class="flex min-w-0 items-center gap-1.5 {wrap ? 'flex-wrap' : ''} {iconsOnNewLine
			? 'flex-col items-start'
			: ''} {className}"
		{title}
		{...rest}
	>
		<span class="flex min-w-0 items-center gap-1.5 {wrap ? 'flex-wrap' : ''}">
			{#if showRawTooltip}
				<Tooltip.Root>
					<Tooltip.Trigger class="flex min-w-0 items-center gap-1.5">
						{@render nameAndBadges()}
					</Tooltip.Trigger>

					<Tooltip.Content>
						<p>{modelId}</p>
					</Tooltip.Content>
				</Tooltip.Root>
			{:else}
				{@render nameAndBadges()}
			{/if}

			{#if !iconsOnNewLine}
				<ModelCapabilityIcons
					{hideCapabilities}
					{hideModalities}
					{modalities}
					{supportsThinking}
					{supportsToolUse}
				/>
			{/if}
		</span>

		{#if iconsOnNewLine || contextLength || sizeRange}
			<span class="inline-flex items-center gap-1.5">
				{#if iconsOnNewLine}
					<ModelCapabilityIcons
						{hideCapabilities}
						{hideModalities}
						{modalities}
						{supportsThinking}
						{supportsToolUse}
					/>
				{/if}

				{#if contextLength}
					<span class="inline-flex items-center gap-1 text-muted-foreground">
						<ScrollText class="h-3 w-3" />

						<span class="text-xs">{formatParameters(contextLength)}</span>
					</span>
				{/if}

				{#if sizeRange}
					<span class="inline-flex items-center gap-1 text-muted-foreground">
						<Database class="h-3 w-3" />

						<span class="text-xs"
							>{HuggingFaceService.formatSizeRange(sizeRange.min, sizeRange.max)}</span
						>
					</span>
				{/if}
			</span>
		{/if}
	</span>
{/if}
