/** @license MIT | @cube-dev/ui-kit v0.135.1 | Cube Dev Team */
import { useEvent } from "../../../_internal/hooks/use-event.js";
import { useRef, useState } from "react";

//#region src/components/overlays/Notifications/use-toast-state.ts
const DEFAULT_TOAST_DURATION = 5e3;
const MAX_TOASTS = 3;
/**
* Generate a deduplication key for a toast.
* Uses JSON.stringify with alphabetically ordered keys to prevent false
* collisions when title/description contains separator characters.
*/
function generateToastDedupeKey(data) {
	if (data.id != null) return String(data.id);
	return JSON.stringify({
		description: typeof data.description === "string" ? data.description : "",
		theme: data.theme ?? "default",
		title: typeof data.title === "string" ? data.title : ""
	});
}
function matchesToastId(item, id) {
	return item.id === id || item.internalId === String(id);
}
function findToast(list, id) {
	return list.find((t) => matchesToastId(t, id));
}
/**
* @param timersRef - Ref to the shared OverlayTimers instance. Accessed only
*   inside callbacks (never during render), so it is guaranteed to be populated.
*/
function useToastState(timersRef) {
	const [toasts, setToasts] = useState([]);
	const toastsRef = useRef(toasts);
	toastsRef.current = toasts;
	const idCounter = useRef(0);
	const removeToast = useEvent((id) => {
		const toast = findToast(toastsRef.current, id);
		if (toast) timersRef.current?.clearToastTimer(toast.internalId);
		setToasts((prev) => prev.map((t) => matchesToastId(t, id) ? {
			...t,
			isExiting: true
		} : t));
	});
	const finalizeToastRemoval = useEvent((internalId) => {
		setToasts((prev) => prev.filter((t) => t.internalId !== internalId));
	});
	return {
		toasts,
		toastsRef,
		addToast: useEvent((data, isProgress = false) => {
			idCounter.current += 1;
			const internalId = `toast-${idCounter.current}-${Date.now()}`;
			const dedupeKey = generateToastDedupeKey(data);
			const duration = isProgress ? null : data.duration ?? DEFAULT_TOAST_DURATION;
			const newToast = {
				...data,
				internalId,
				isProgress,
				dedupeKey,
				createdAt: Date.now()
			};
			const existingToast = toastsRef.current.find((t) => t.dedupeKey === dedupeKey && !t.isExiting);
			if (existingToast) timersRef.current?.clearToastTimer(existingToast.internalId);
			let wasEvicted = false;
			const evictedIds = [];
			setToasts((prev) => {
				let newToasts = prev;
				if (existingToast) newToasts = newToasts.map((t) => t.internalId === existingToast.internalId ? {
					...t,
					isExiting: true
				} : t);
				newToasts = [...newToasts, newToast];
				const activeToasts = newToasts.filter((t) => !t.isExiting);
				const progressToasts = activeToasts.filter((t) => t.isProgress);
				const temporalToasts = activeToasts.filter((t) => !t.isProgress);
				while (activeToasts.length > MAX_TOASTS) if (temporalToasts.length > 1 || progressToasts.length < MAX_TOASTS) {
					const oldestTemporal = temporalToasts.shift();
					if (oldestTemporal) {
						evictedIds.push(oldestTemporal.internalId);
						newToasts = newToasts.map((t) => t.internalId === oldestTemporal.internalId ? {
							...t,
							isExiting: true
						} : t);
						const idx = activeToasts.findIndex((t) => t.internalId === oldestTemporal.internalId);
						if (idx !== -1) activeToasts.splice(idx, 1);
						if (oldestTemporal.internalId === internalId) wasEvicted = true;
					} else break;
				} else break;
				return newToasts;
			});
			for (const evictedId of evictedIds) timersRef.current?.clearToastTimer(evictedId);
			if (!wasEvicted && duration != null && duration > 0) timersRef.current?.startToastTimer(internalId, data.id ?? internalId, duration);
			return data.id ?? internalId;
		}),
		removeToast,
		updateToast: useEvent((id, data) => {
			setToasts((prev) => prev.map((t) => matchesToastId(t, id) ? {
				...t,
				...data
			} : t));
		}),
		finalizeToastRemoval
	};
}

//#endregion
export { useToastState };
//# sourceMappingURL=use-toast-state.js.map