import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { getNotifications, getUnreadCount, markAllNotificationsRead, markNotificationRead, } from "../services/notificationService";
import { applyMarkAllReadToNotifications, applyMarkReadToNotifications, buildNotificationQuery, getNextOffsetAfterMarkRead, getNextOffsetAfterRealtime, mergeNotificationLists, } from "./notificationListState";
import { resolveNotificationAction } from "./notificationRoutes";
import { useNotificationSubscriptions } from "./useNotificationSubscriptions";
function safeParseContext(contextJson) {
    if (!contextJson)
        return undefined;
    try {
        return JSON.parse(contextJson);
    }
    catch {
        return undefined;
    }
}
const DEFAULT_PAGE_SIZE = 50;
const NOTIFICATION_REFRESH_DEDUPE_MS = 1_000;
const notificationRefreshInflight = new Map();
const notificationRefreshCache = new Map();
async function fetchNotificationSnapshot(showAll, pageSize) {
    const cacheKey = `${showAll}:${pageSize}`;
    const cached = notificationRefreshCache.get(cacheKey);
    if (cached &&
        Date.now() - cached.fetchedAt < NOTIFICATION_REFRESH_DEDUPE_MS) {
        return cached;
    }
    const inflight = notificationRefreshInflight.get(cacheKey);
    if (inflight) {
        return inflight;
    }
    const request = (async () => {
        const notificationQuery = buildNotificationQuery({
            showAll,
            skip: 0,
            take: pageSize,
        });
        const [listResult, countResult] = await Promise.all([
            getNotifications(notificationQuery),
            getUnreadCount(),
        ]);
        const snapshot = {
            notifications: listResult.type === "success" ? listResult.data || [] : [],
            unreadCount: countResult.type === "success"
                ? Math.max(0, countResult.data?.count || 0)
                : 0,
            hasMore: listResult.type === "success"
                ? (listResult.data || []).length === pageSize
                : false,
            fetchedAt: Date.now(),
        };
        notificationRefreshCache.set(cacheKey, snapshot);
        return snapshot;
    })().finally(() => {
        notificationRefreshInflight.delete(cacheKey);
    });
    notificationRefreshInflight.set(cacheKey, request);
    return request;
}
export function useNotifications(editContext, options) {
    const showAll = options?.showAll ?? false;
    const pageSize = options?.pageSize ?? DEFAULT_PAGE_SIZE;
    const [notifications, setNotifications] = useState([]);
    const [unreadCount, setUnreadCount] = useState(0);
    const [loading, setLoading] = useState(false);
    const [loadingMore, setLoadingMore] = useState(false);
    const [hasMore, setHasMore] = useState(false);
    const [nextOffset, setNextOffset] = useState(0);
    const notificationIdsRef = useRef(new Set());
    const { subscriptions, unsubscribeFromTarget } = useNotificationSubscriptions();
    const updateNotifications = useCallback((updater) => {
        setNotifications((current) => {
            const next = typeof updater === "function" ? updater(current) : updater;
            notificationIdsRef.current = new Set(next.map((notification) => notification.id));
            return next;
        });
    }, []);
    const refresh = useCallback(async () => {
        setLoading(true);
        try {
            const snapshot = await fetchNotificationSnapshot(showAll, pageSize);
            updateNotifications(snapshot.notifications);
            setNextOffset(snapshot.notifications.length);
            setHasMore(snapshot.hasMore);
            setUnreadCount(snapshot.unreadCount);
        }
        finally {
            setLoading(false);
        }
    }, [pageSize, showAll, updateNotifications]);
    useEffect(() => {
        void refresh();
    }, [refresh]);
    const loadMore = useCallback(async () => {
        if (loading || loadingMore || !hasMore)
            return;
        setLoadingMore(true);
        try {
            const result = await getNotifications(buildNotificationQuery({
                showAll,
                skip: nextOffset,
                take: pageSize,
            }));
            if (result.type !== "success")
                return;
            const nextPage = result.data || [];
            updateNotifications((prev) => mergeNotificationLists(prev, nextPage));
            setNextOffset((prev) => prev + nextPage.length);
            setHasMore(nextPage.length === pageSize);
        }
        finally {
            setLoadingMore(false);
        }
    }, [
        hasMore,
        loading,
        loadingMore,
        nextOffset,
        pageSize,
        showAll,
        updateNotifications,
    ]);
    useEffect(() => {
        const addListener = editContext?.addSocketMessageListener;
        if (!addListener)
            return;
        const unsubscribe = addListener((message) => {
            if (message?.type !== "user:notification")
                return;
            const payload = (message?.payload || {});
            const priority = payload.priority || "normal";
            const incoming = {
                id: payload.id || crypto.randomUUID(),
                userId: editContext?.user?.name || "",
                type: payload.notificationType || "notification",
                priority,
                title: payload.title || "Notification",
                message: payload.message || "",
                contextJson: payload.context ? JSON.stringify(payload.context) : null,
                isRead: false,
                createdAt: payload.createdAt || new Date().toISOString(),
            };
            const isNewNotification = !notificationIdsRef.current.has(incoming.id);
            if (isNewNotification) {
                notificationIdsRef.current.add(incoming.id);
            }
            updateNotifications((prev) => mergeNotificationLists([incoming], prev));
            if (isNewNotification) {
                setNextOffset((prev) => getNextOffsetAfterRealtime(prev));
                setUnreadCount((prev) => prev + 1);
            }
            if (priority === "high") {
                const notificationWithContext = {
                    ...incoming,
                    context: payload.context,
                };
                const action = resolveNotificationAction(editContext, notificationWithContext);
                toast.info(incoming.title, {
                    description: incoming.message,
                    duration: 30000,
                    ...(action
                        ? {
                            action: {
                                label: "Open",
                                onClick: () => {
                                    void action.open();
                                },
                            },
                        }
                        : {}),
                });
            }
        });
        return () => {
            unsubscribe();
        };
    }, [editContext, showAll, updateNotifications]);
    const markRead = useCallback(async (id) => {
        const result = await markNotificationRead(id);
        if (result.type !== "success")
            return false;
        updateNotifications((prev) => applyMarkReadToNotifications(prev, id, showAll));
        setNextOffset((prev) => getNextOffsetAfterMarkRead(prev, showAll));
        setUnreadCount((prev) => Math.max(0, prev - 1));
        return true;
    }, [showAll, updateNotifications]);
    const markAllRead = useCallback(async () => {
        const result = await markAllNotificationsRead();
        if (result.type !== "success")
            return false;
        updateNotifications((prev) => applyMarkAllReadToNotifications(prev, showAll));
        setNextOffset(showAll ? nextOffset : 0);
        setHasMore(showAll ? hasMore : false);
        setUnreadCount(0);
        return true;
    }, [hasMore, nextOffset, showAll, updateNotifications]);
    const unsubscribe = useCallback(async (targetType, targetId) => {
        const result = await unsubscribeFromTarget({ targetType, targetId });
        return result.type === "success";
    }, [unsubscribeFromTarget]);
    const mappedNotifications = useMemo(() => notifications.map((notification) => ({
        ...notification,
        context: safeParseContext(notification.contextJson),
    })), [notifications]);
    return {
        notifications: mappedNotifications,
        subscriptions,
        unreadCount,
        loading,
        loadingMore,
        hasMore,
        refresh,
        loadMore,
        markRead,
        markAllRead,
        unsubscribe,
    };
}
//# sourceMappingURL=useNotifications.js.map