import type { TimelineTrack } from "@/timeline";
import { timelineTimeToPixels } from "@/timeline/pixel-utils";
import {
	TIMELINE_CONTENT_TOP_PADDING_PX,
} from "./layout";
import { getCumulativeHeightBefore, getTrackHeight } from "./track-layout";

type TimelineElementRef = { trackId: string; elementId: string };

interface SelectionRectangle {
	left: number;
	top: number;
	right: number;
	bottom: number;
}

function getNormalizedRectangle({
	startPos,
	endPos,
}: {
	startPos: { x: number; y: number };
	endPos: { x: number; y: number };
}): SelectionRectangle {
	return {
		left: Math.min(startPos.x, endPos.x),
		top: Math.min(startPos.y, endPos.y),
		right: Math.max(startPos.x, endPos.x),
		bottom: Math.max(startPos.y, endPos.y),
	};
}

function getSelectionRectangleInContent({
	container,
	scrollContainer,
	startPos,
	endPos,
}: {
	container: HTMLElement;
	scrollContainer: HTMLDivElement | null;
	startPos: { x: number; y: number };
	endPos: { x: number; y: number };
}): SelectionRectangle {
	const containerRect = container.getBoundingClientRect();
	const scrollRect = scrollContainer?.getBoundingClientRect() ?? containerRect;
	const scrollLeft = scrollContainer?.scrollLeft ?? 0;
	const scrollTop = scrollContainer?.scrollTop ?? 0;

	const adjustedStart = {
		x: startPos.x - containerRect.left + scrollLeft,
		y: startPos.y - scrollRect.top + scrollTop,
	};
	const adjustedEnd = {
		x: endPos.x - containerRect.left + scrollLeft,
		y: endPos.y - scrollRect.top + scrollTop,
	};

	return getNormalizedRectangle({
		startPos: adjustedStart,
		endPos: adjustedEnd,
	});
}

function isRectangleIntersecting({
	elementRectangle,
	selectionRectangle,
}: {
	elementRectangle: SelectionRectangle;
	selectionRectangle: SelectionRectangle;
}): boolean {
	return !(
		elementRectangle.right < selectionRectangle.left ||
		elementRectangle.left > selectionRectangle.right ||
		elementRectangle.bottom < selectionRectangle.top ||
		elementRectangle.top > selectionRectangle.bottom
	);
}

export function resolveTimelineElementIntersections({
	container,
	scrollContainer,
	tracks,
	zoomLevel,
	startPos,
	currentPos,
}: {
	container: HTMLElement;
	scrollContainer: HTMLDivElement | null;
	tracks: TimelineTrack[];
	zoomLevel: number;
	startPos: { x: number; y: number };
	currentPos: { x: number; y: number };
}): TimelineElementRef[] {
	const selectionRectangle = getSelectionRectangleInContent({
		container,
		scrollContainer,
		startPos,
		endPos: currentPos,
	});
	const selectedElements: TimelineElementRef[] = [];

	for (const [trackIndex, track] of tracks.entries()) {
		const trackTop = getCumulativeHeightBefore({
			tracks,
			trackIndex,
		});
		const trackHeight = getTrackHeight({ type: track.type });
		const elementTop = TIMELINE_CONTENT_TOP_PADDING_PX + trackTop;
		const elementBottom = elementTop + trackHeight;

		for (const element of track.elements) {
			const elementLeft = timelineTimeToPixels({ time: element.startTime, zoomLevel });
			const elementRight = timelineTimeToPixels({ time: element.startTime + element.duration, zoomLevel });
			const elementRectangle = {
				left: elementLeft,
				top: elementTop,
				right: elementRight,
				bottom: elementBottom,
			};

			if (
				isRectangleIntersecting({
					elementRectangle,
					selectionRectangle,
				})
			) {
				selectedElements.push({
					trackId: track.id,
					elementId: element.id,
				});
			}
		}
	}

	return selectedElements;
}
