<script lang="ts">
import * as m from '$lib/paraglide/messages.js';
import LetterCard from './LetterCard.svelte';
import { entryKey } from './entryKey';
import { getAccentConfig } from './eventCardConfig';
import { timelineDateLabel } from './dateLabel';
import { CLUSTER_PREVIEW } from './eventClustering';
import type { components } from '$lib/generated/api';

type TimelineEntryDTO = components['schemas']['TimelineEntryDTO'];

/**
 * A curated event with linked letters, rendered as one contained card: the event IS the card's
 * header (so its title reads once — never also as a floating pill, #850 REQ-002), and its letters
 * sit inside as compact `.lcard.ev` cards.
 *
 * - Same-year event (`event` given): the header carries the accent glyph + sr-only label, the
 *   title, a `{date} · {kuratiert|abgeleitet}` subtitle, the letter count, and — for a curator on
 *   a curated event — an edit link to `/zeitstrahl/events/{eventId}/edit` (REQ-002).
 * - Cross-year (`title` given, no `event`): a plain `✉ {title}` text header, no edit link, no pill
 *   chrome — it holds that other year's linked letters (REQ-004).
 *
 * A card shows its first {@link CLUSTER_PREVIEW} letters, then a keyboard-operable show-more/less
 * toggle reveals/collapses the rest instead of flooding the timeline (REQ-003).
 */
let {
	letters,
	event = undefined,
	title = '',
	canWrite = false
}: {
	letters: TimelineEntryDTO[];
	/** The same-year curated event whose letters this card holds — renders as the header. */
	event?: TimelineEntryDTO;
	/** Header label for a cross-year card (no `event`). */
	title?: string;
	canWrite?: boolean;
} = $props();

const count = $derived(letters.length);

// Event-as-header: a same-year curated event renders as this card's header, mirroring EventPill —
// glyph + title + date · provenance + an edit pencil for a curator. The title is never repeated
// as a separate floating pill (REQ-002).
const accent = $derived(event ? getAccentConfig(event) : null);
const eventDateLabel = $derived(
	event ? timelineDateLabel(event.eventDate, event.precision, event.eventDateEnd) : null
);
const provenance = $derived(
	event?.derived ? m.timeline_provenance_derived() : m.timeline_provenance_curated()
);
const eventSubtitle = $derived(eventDateLabel ? `${eventDateLabel} · ${provenance}` : provenance);
const canEdit = $derived(canWrite && !!event && !event.derived && event.eventId != null);

// First-5 preview + show-more (REQ-003): a large cluster stays readable instead of dumping every
// card into the timeline.
let expanded = $state(false);
const visible = $derived(expanded ? letters : letters.slice(0, CLUSTER_PREVIEW));
const hiddenCount = $derived(letters.length - CLUSTER_PREVIEW);
</script>

<section
	class="my-3 overflow-hidden rounded-md border border-l-2 border-line border-l-brand-mint bg-surface shadow-sm"
	data-testid="event-card"
>
	{#if event && accent}
		<!-- A same-year curated event IS the card header — its title reads once here, never also
		     as a floating pill (REQ-002). Glyph is aria-hidden with an sr-only label sibling; the
		     edit pencil mirrors EventPill's gate (REQ-010). -->
		<header
			data-testid="event-header"
			class="flex items-center gap-2 border-b border-line bg-canvas px-3 py-2"
		>
			<span
				class="flex h-7 w-7 shrink-0 items-center justify-center rounded-full {accent.accent ===
				'curated'
					? 'bg-brand-mint text-brand-navy'
					: 'bg-brand-navy text-brand-mint'}"
			>
				<span aria-hidden="true">{accent.glyph}</span>
				<span class="sr-only">{accent.label}</span>
			</span>
			<span class="min-w-0 text-left">
				<span class="block font-serif text-sm font-bold whitespace-pre-line text-brand-navy"
					>{event.title}</span
				>
				<span class="block font-sans text-xs text-ink-3">
					{eventSubtitle} <span data-testid="event-count">· {count}</span>
				</span>
			</span>
			{#if canEdit}
				<a
					data-testid="event-edit"
					href="/zeitstrahl/events/{event.eventId}/edit"
					class="ml-auto rounded-sm px-1 font-sans text-xs text-ink-3 hover:text-brand-navy focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-navy"
				>
					<span aria-hidden="true">✎</span>
					<span class="sr-only">{m.btn_edit()}</span>
				</a>
			{/if}
		</header>
	{:else}
		<!-- Cross-year card (REQ-004): the same event's letters in another year band get a plain
		     ✉ text header — no pill chrome, no edit link. -->
		<header
			data-testid="event-header"
			class="flex items-center gap-2 border-b border-line px-3 py-2"
		>
			<span class="font-serif text-sm font-bold whitespace-pre-line text-ink">
				<span aria-hidden="true">✉</span>
				{title}
			</span>
			<span data-testid="event-count" class="font-sans text-xs text-ink-3">· {count}</span>
		</header>
	{/if}

	<div class="px-3 py-2">
		<ul class="space-y-1.5">
			{#each visible as letter (entryKey(letter))}
				<li>
					<LetterCard entry={letter} variant="event" compact={true} />
				</li>
			{/each}
		</ul>
		{#if hiddenCount > 0}
			<button
				type="button"
				data-testid="bucket-show-more"
				aria-expanded={expanded}
				onclick={() => (expanded = !expanded)}
				style="display: inline-flex; align-items: center; min-height: 44px"
				class="mt-1 px-1 font-sans text-xs font-semibold text-brand-navy hover:underline focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-navy"
			>
				{expanded
					? m.timeline_bucket_show_less()
					: m.timeline_bucket_show_more({ count: hiddenCount })}
			</button>
		{/if}
	</div>
</section>
