// (C) 2025 GoodData Corporation
import { useCallback, useEffect, useRef, useState } from "react";
import { createContextStore, useAutoupdateRef } from "@gooddata/sdk-ui";
const DEFAULT_DURATION = 2500;
let toastsCenterCounter = 0;
/**
 * @internal
 */
export const ToastsCenterContext = createContextStore("ToastsCenter");
/**
 * @internal
 */
export const useToastsCenterValue = (onDismissMessage) => {
    const [toastsCenterId] = useState(`toasts-${toastsCenterCounter++}`);
    const toastCounterRef = useRef(0);
    const [messages, setMessages] = useState([]);
    const [latestMessage, setLatestMessage] = useState(null);
    const parentContext = ToastsCenterContext.useContextStoreOptional((ctx) => ctx);
    const parentContextRef = useAutoupdateRef(parentContext);
    const hasParentContext = !!parentContext;
    const dismissTimeoutsRef = useRef(new Set());
    const dismissTimeouts = useCallback(() => {
        dismissTimeoutsRef.current.forEach((timeoutId) => {
            clearTimeout(timeoutId);
        });
    }, []);
    // Dismiss timeouts when the component unmounts
    useEffect(() => {
        return () => {
            dismissTimeouts();
        };
    }, [dismissTimeouts]);
    const messagesRef = useAutoupdateRef(messages);
    // When there is a new parent, transfer my messages to it and dismiss my timeouts
    // The parent will register its own timeouts
    // Known issue: The dismiss duration is reset on transferring to the parent.
    useEffect(() => {
        if (!hasParentContext) {
            return undefined;
        }
        parentContextRef.current?.addExistingMessages(messagesRef.current);
        setMessages(() => []);
        dismissTimeouts();
    }, [dismissTimeouts, hasParentContext, messagesRef, parentContextRef]);
    const removeMessage = useCallback((id, preventDismissHandler) => {
        setMessages((prev) => {
            const messageToRemove = prev.find((m) => m.id === id);
            if (!messageToRemove) {
                return prev;
            }
            if (!preventDismissHandler) {
                messageToRemove.onDismiss?.();
                onDismissMessage?.(id);
            }
            return prev.filter((m) => m !== messageToRemove);
        });
    }, [onDismissMessage]);
    const removeAllMessages = useCallback((preventDismissHandler) => {
        messages.forEach((message) => removeMessage(message.id, preventDismissHandler));
    }, [messages, removeMessage]);
    const addExistingMessage = useCallback((existingMessage) => {
        removeMessage(existingMessage.id, true);
        setMessages((currentMessages) => [...currentMessages, existingMessage]);
        setLatestMessage((currentLatest) => {
            const currentLatestCreatedAt = currentLatest?.createdAt ?? -Infinity;
            return existingMessage.createdAt > currentLatestCreatedAt ? existingMessage : currentLatest;
        });
        const duration = existingMessage.duration ?? DEFAULT_DURATION;
        if (duration && isFinite(duration)) {
            const timeoutId = setTimeout(() => {
                removeMessage(existingMessage.id);
                dismissTimeoutsRef.current.delete(timeoutId);
            }, duration);
            dismissTimeoutsRef.current.add(timeoutId);
        }
    }, [removeMessage]);
    const addExistingMessages = useCallback((existingMessages) => {
        existingMessages.forEach(addExistingMessage);
    }, [addExistingMessage]);
    const addMessage = useCallback((newMessage) => {
        const createdMessage = {
            createdAt: new Date().getTime(),
            id: `${toastsCenterId}:${toastCounterRef.current++}`,
            ...newMessage,
        };
        addExistingMessage(createdMessage);
        return createdMessage;
    }, [addExistingMessage, toastsCenterId]);
    return {
        ...(parentContext ?? {
            messages,
            removeMessage,
            removeAllMessages,
            addMessage,
            addExistingMessage,
            addExistingMessages,
            latestMessage,
        }),
        hasParentContext,
    };
};
