<script lang="ts">
import * as m from '$lib/paraglide/messages.js';
import { relativeTime } from '$lib/shared/utils/time';
import { buildCommentHref } from '$lib/shared/discussion/commentDeepLink';
import type { components } from '$lib/generated/api';

type ActivityFeedItemDTO = components['schemas']['ActivityFeedItemDTO'];
type Variant = 'comment' | 'for-you' | 'rollup' | 'simple';

interface Props {
	item: ActivityFeedItemDTO;
}

const { item }: Props = $props();

const variant: Variant = $derived(
	item.kind === 'COMMENT_ADDED'
		? 'comment'
		: item.youMentioned
			? 'for-you'
			: item.count > 1
				? 'rollup'
				: 'simple'
);

function verbSingleton(kind: string, actor: string, doc: string): string {
	switch (kind) {
		case 'TEXT_SAVED':
			return m.chronik_singleton_text_saved({ actor, doc });
		case 'FILE_UPLOADED':
			return m.chronik_singleton_uploaded({ actor, doc });
		case 'BLOCK_REVIEWED':
			return m.chronik_singleton_reviewed({ actor, doc });
		case 'ANNOTATION_CREATED':
			return m.chronik_singleton_annotated({ actor, doc });
		case 'COMMENT_ADDED':
			return m.chronik_comment_added({ actor, doc });
		case 'MENTION_CREATED':
			return m.chronik_mention_created({ actor, doc });
		default:
			return `${actor} · ${doc}`;
	}
}

function verbRollup(kind: string, actor: string, doc: string, count: number): string {
	switch (kind) {
		case 'TEXT_SAVED':
			return m.chronik_rollup_text_saved({ actor, doc, count });
		case 'FILE_UPLOADED':
			return m.chronik_rollup_uploaded({ actor, count });
		case 'BLOCK_REVIEWED':
			return m.chronik_rollup_reviewed({ actor, doc, count });
		case 'ANNOTATION_CREATED':
			return m.chronik_rollup_annotated({ actor, doc, count });
		default:
			return verbSingleton(kind, actor, doc);
	}
}

function formatTimeHHMM(iso: string): string {
	const d = new Date(iso);
	return new Intl.DateTimeFormat('de-DE', {
		hour: '2-digit',
		minute: '2-digit',
		hour12: false
	}).format(d);
}

const actorName: string = $derived(item.actor?.name ?? item.actor?.initials ?? '?');
const docTitle: string = $derived(item.documentTitle);

// We split the translated verb around the document title so the title can be
// rendered as a styled <span> inside the <a> without nesting anchors. Using a
// non-printable sentinel (U+0001) as the {doc} interpolation value lets us
// split the compiled message regardless of what the actual title contains —
// empty strings, short substrings that also appear in the verb, and any
// translator sentence order all work without special cases.
const SENTINEL = '\u0001';

const verbText: string = $derived(
	variant === 'rollup'
		? verbRollup(item.kind, actorName, SENTINEL, item.count)
		: verbSingleton(item.kind, actorName, SENTINEL)
);

const timeLabel: string = $derived(
	variant === 'rollup' && item.happenedAtUntil
		? `${formatTimeHHMM(item.happenedAt)}\u2013${formatTimeHHMM(item.happenedAtUntil)}`
		: relativeTime(item.happenedAt)
);

const verbParts: { before: string; after: string } = $derived.by(() => {
	const idx = verbText.indexOf(SENTINEL);
	if (idx === -1) return { before: verbText, after: '' };
	return {
		before: verbText.slice(0, idx),
		after: verbText.slice(idx + SENTINEL.length)
	};
});

const rowHref: string = $derived(
	item.commentId
		? buildCommentHref(item.documentId, item.commentId, item.annotationId ?? null)
		: `/documents/${item.documentId}`
);
</script>

<a
	href={rowHref}
	data-variant={variant}
	aria-label={variant === 'comment'
		? item.commentPreview
			? `${m.chronik_comment_added({ actor: actorName, doc: docTitle })} — ${item.commentPreview}`
			: m.chronik_comment_added({ actor: actorName, doc: docTitle })
		: undefined}
	class="group flex items-start gap-3 p-3 transition-colors hover:bg-muted/50 focus-visible:ring-2 focus-visible:ring-focus-ring focus-visible:outline-none
		{variant === 'for-you' ? 'border-l-[3px] border-accent bg-accent-bg/10' : ''}"
>
	<!-- Avatar -->
	{#if item.actor}
		<span
			class="mt-0.5 inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full font-sans text-sm font-bold text-white"
			style="background:{item.actor.color}"
			aria-hidden="true"
		>
			{item.actor.initials}
		</span>
	{:else}
		<span
			data-testid="chronik-avatar-fallback"
			class="mt-0.5 inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-line font-sans text-sm text-ink-3"
			aria-hidden="true"
		>
			?
		</span>
	{/if}

	<!-- For-you marker (hidden on mobile) -->
	{#if variant === 'for-you'}
		<span
			data-testid="chronik-foryou-marker"
			aria-hidden="true"
			class="mt-1 hidden h-6 w-6 shrink-0 items-center justify-center rounded-full bg-accent-bg font-sans text-xs font-bold text-accent sm:inline-flex"
		>
			@
		</span>
	{/if}

	<!-- Body -->
	<div class="min-w-0 flex-1">
		<p class="font-sans text-sm leading-snug text-ink">
			{verbParts.before}<span
				data-testid="chronik-doc-title"
				class="underline decoration-accent underline-offset-2">{docTitle}</span
			>{verbParts.after}
			{#if variant === 'rollup'}
				<span
					data-testid="chronik-count-badge"
					class="ml-1 inline-block rounded-sm bg-primary px-2 py-0.5 font-sans text-xs text-primary-fg"
				>
					{item.count}
				</span>
			{/if}
		</p>

		{#if variant === 'comment'}
			<p
				data-testid="chronik-comment-preview"
				class="mt-1 line-clamp-1 font-serif text-sm text-ink-2 italic sm:line-clamp-2"
			>
				{item.commentPreview ?? '„…"'}
			</p>
		{/if}

		<p class="mt-0.5 font-sans text-xs text-ink-3">{timeLabel}</p>
	</div>
</a>
