<script lang="ts">
import { NODE_W, NODE_H } from '$lib/person/genealogy/layout/buildLayout';
import { DIMMED_OPACITY } from '$lib/person/genealogy/layout/highlightLineage';
import type { components } from '$lib/generated/api';

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

interface Props {
	node: PersonNodeDTO;
	pos: { x: number; y: number };
	selected: boolean;
	/** Dim the node's outline + labels when a lineage is highlighted and this person is outside it. */
	dimmed?: boolean;
	onSelect: (id: string) => void;
}

let { node, pos, selected, dimmed = false, onSelect }: Props = $props();

// Each node owns its own focus-ring state (the focus ring is decorative; the
// `<g role="button">` is the real focus target).
let focused = $state(false);

function handleKey(event: KeyboardEvent) {
	if (event.key === 'Enter' || event.key === ' ') {
		event.preventDefault();
		onSelect(node.id);
	}
}

const datesLabel = $derived(
	node.birthYear || node.deathYear ? `, ${node.birthYear ?? '?'}–${node.deathYear ?? ''}` : ''
);
</script>

<g
	role="button"
	tabindex="0"
	aria-label="{node.displayName}{datesLabel}"
	aria-expanded={selected}
	transform="translate({pos.x}, {pos.y})"
	onclick={() => onSelect(node.id)}
	onkeydown={handleKey}
	onfocus={() => (focused = true)}
	onblur={() => (focused = false)}
	class="cursor-pointer focus:outline-none"
>
	{#if focused}
		<rect
			x="-3"
			y="-3"
			width={NODE_W + 6}
			height={NODE_H + 6}
			rx="6"
			fill="none"
			stroke="var(--c-focus-ring)"
			stroke-width="2"
		/>
	{/if}
	<!-- Opaque card fill — full strength even when dimmed, so the connectors
	     drawn beneath the node never bleed through. The lineage dim lives on the
	     content group below; group opacity here would make the fill translucent. -->
	<rect
		width={NODE_W}
		height={NODE_H}
		rx="4"
		fill={selected ? 'var(--c-primary)' : 'var(--c-surface)'}
	/>
	<!-- Outline + labels carry the lineage focus+dim; the box stays opaque. -->
	<g class="lineage-fade" opacity={dimmed ? DIMMED_OPACITY : undefined}>
		<rect
			width={NODE_W}
			height={NODE_H}
			rx="4"
			fill="none"
			stroke="var(--c-primary)"
			stroke-width="1.5"
		/>
		{#if selected}
			<rect width="4" height={NODE_H} rx="2" fill="var(--c-accent)" />
		{/if}
		<text
			x={NODE_W / 2}
			y={NODE_H / 2 - 6}
			text-anchor="middle"
			font-family="serif"
			font-size="16"
			fill={selected ? 'var(--c-primary-fg)' : 'var(--c-ink)'}
		>
			{node.displayName}
		</text>
		{#if node.birthYear || node.deathYear}
			<text
				x={NODE_W / 2}
				y={NODE_H / 2 + 12}
				text-anchor="middle"
				font-family="sans-serif"
				font-size="12"
				fill={selected ? 'var(--c-primary-fg)' : 'var(--c-ink-3)'}
				opacity={selected ? 0.75 : 1}
			>
				{node.birthYear ?? '?'}–{node.deathYear ?? ''}
			</text>
		{/if}
	</g>
</g>

<style>
/* Ease the lineage focus+dim transition; instant for reduced-motion users. */
.lineage-fade {
	transition: opacity 200ms ease;
}
@media (prefers-reduced-motion: reduce) {
	.lineage-fade {
		transition: none;
	}
}
</style>
