<script lang="ts">
import type { Annotation } from '$lib/shared/types';
import AnnotationShape from './AnnotationShape.svelte';

type DrawRect = {
	x: number;
	y: number;
	width: number;
	height: number;
};

let {
	annotations = [],
	canDraw,
	color,
	blockNumbers = {},
	activeAnnotationId = null,
	dimmed = false,
	flashAnnotationId = null,
	onDraw,
	onAnnotationClick,
	onAnnotationFocus
}: {
	annotations: Annotation[];
	canDraw: boolean;
	color: string;
	blockNumbers?: Record<string, number>;
	activeAnnotationId?: string | null;
	dimmed?: boolean;
	flashAnnotationId?: string | null;
	onDraw: (rect: DrawRect) => void;
	onAnnotationClick?: (id: string) => void;
	onAnnotationFocus?: (id: string) => void;
} = $props();

let drawStart = $state<{ x: number; y: number } | null>(null);
let drawRect = $state<DrawRect | null>(null);

function getNormalizedCoords(event: PointerEvent, element: HTMLElement): { x: number; y: number } {
	const rect = element.getBoundingClientRect();
	return {
		x: (event.clientX - rect.left) / rect.width,
		y: (event.clientY - rect.top) / rect.height
	};
}

function handlePointerDown(event: PointerEvent) {
	if (!canDraw) return;

	if ((event.target as HTMLElement).closest('[data-annotation]')) return;

	const container = event.currentTarget as HTMLElement;
	container.setPointerCapture(event.pointerId);

	const coords = getNormalizedCoords(event, container);
	drawStart = coords;
	drawRect = { x: coords.x, y: coords.y, width: 0, height: 0 };
}

function handlePointerMove(event: PointerEvent) {
	if (!canDraw || !drawStart) return;

	const container = event.currentTarget as HTMLElement;
	const coords = getNormalizedCoords(event, container);

	const x = Math.min(drawStart.x, coords.x);
	const y = Math.min(drawStart.y, coords.y);
	const width = Math.abs(coords.x - drawStart.x);
	const height = Math.abs(coords.y - drawStart.y);

	drawRect = { x, y, width, height };
}

function handlePointerUp(event: PointerEvent) {
	if (!canDraw || !drawStart || !drawRect) return;

	const container = event.currentTarget as HTMLElement;
	const coords = getNormalizedCoords(event, container);

	const x = Math.min(drawStart.x, coords.x);
	const y = Math.min(drawStart.y, coords.y);
	const width = Math.abs(coords.x - drawStart.x);
	const height = Math.abs(coords.y - drawStart.y);

	if (width > 0.01 && height > 0.01) {
		onDraw({ x, y, width, height });
	}

	drawStart = null;
	drawRect = null;
}

let hoveredId = $state<string | null>(null);

const containerStyle = $derived(
	`position: absolute; top: 0; left: 0; width: 100%; height: 100%;${canDraw ? ' cursor: crosshair; touch-action: none;' : ''}`
);
</script>

<div
	style={containerStyle}
	role="presentation"
	onpointerdown={handlePointerDown}
	onpointermove={handlePointerMove}
	onpointerup={handlePointerUp}
>
	{#each annotations as annotation (annotation.id)}
		<AnnotationShape
			annotation={annotation}
			isHovered={hoveredId === annotation.id}
			isActive={annotation.id === activeAnnotationId}
			isResizable={canDraw && annotation.id === activeAnnotationId && !annotation.polygon}
			faded={!dimmed && !!activeAnnotationId && annotation.id !== activeAnnotationId}
			dimmed={dimmed}
			blockNumber={blockNumbers[annotation.id]}
			isFlashing={flashAnnotationId === annotation.id}
			showDelete={canDraw}
			onclick={() => onAnnotationClick?.(annotation.id)}
			onfocus={() => onAnnotationFocus?.(annotation.id)}
			onpointerenter={() => (hoveredId = annotation.id)}
			onpointerleave={() => (hoveredId = null)}
		/>
	{/each}

	{#if drawRect && drawRect.width > 0}
		<div
			style="
				position: absolute;
				left: {drawRect.x * 100}%;
				top: {drawRect.y * 100}%;
				width: {drawRect.width * 100}%;
				height: {drawRect.height * 100}%;
				border: 2px dashed {color};
				opacity: 0.3;
				pointer-events: none;
			"
		></div>
	{/if}
</div>
