// (C) 2026 GoodData Corporation
import { useCallback, useRef, useState } from "react";
import { debounce, isEmpty } from "lodash-es";
const ITEMS_PER_PAGE = 50;
const DEFAULT_INSIGHT_SORT = ["modifiedAt,createdAt,title,desc"];
/**
 * Hook to fetch insights paged list
 * @param backend - analytical backend
 * @param workspaceId - workspace id
 * @param author - author
 * @param tabsIds - tabs ids
 * @param tags - fetch only the insights with these tags
 * @param excludeTags - omit insights with these tags during fetch
 * @returns useInsightPagedList result
 *
 * @internal
 */
export function useInsightPagedList({ backend, workspaceId, author, tabsIds, tags, excludeTags, }) {
    const [items, setItems] = useState([]);
    const [totalItemsCount, setTotalItemsCount] = useState(undefined);
    const [isLoading, setIsLoading] = useState(false);
    const [isNextPageLoading, setIsNextPageLoading] = useState(false);
    const [initialLoadCompleted, setInitialLoadCompleted] = useState(false);
    const [currentPage, setCurrentPage] = useState(0);
    const [search, setSearch] = useState("");
    const [selectedTabId, setSelectedTabId] = useState(tabsIds.my);
    const abortControllerRef = useRef(null);
    const initialLoadCompletedRef = useRef(false);
    const totalItems = totalItemsCount ?? items.length;
    const hasNextPage = totalItems > items.length;
    const skeletonItemsCount = hasNextPage ? Math.min(ITEMS_PER_PAGE, totalItems - items.length) : 0;
    const fetchItems = useCallback(async (params) => {
        const { page, search: searchValue, tabId = tabsIds.my, resetItems = false } = params;
        // Cancel any ongoing request
        if (abortControllerRef.current) {
            abortControllerRef.current.abort();
        }
        abortControllerRef.current = new AbortController();
        // Capture the current signal before the await to check the correct one after
        const currentSignal = abortControllerRef.current.signal;
        const isFirstPage = page === 0;
        // Show global loading when resetting items (tab switch, search) or on first page
        if (resetItems || isFirstPage) {
            setIsLoading(true);
            // Clear items immediately to show loading spinner
            if (resetItems) {
                setItems([]);
                setTotalItemsCount(undefined);
            }
        }
        else {
            setIsNextPageLoading(true);
        }
        try {
            const query = backend
                .workspace(workspaceId)
                .insights()
                .getInsightsQuery()
                .withSize(ITEMS_PER_PAGE)
                .withPage(page)
                .withSorting(DEFAULT_INSIGHT_SORT);
            const searchedTitle = searchValue || undefined;
            const searchedAuthor = tabId === tabsIds.my && isEmpty(searchValue) ? author : undefined;
            if (searchedAuthor) {
                query.withInclude(["createdBy", "modifiedBy"]);
            }
            const filter = {
                ...((tags?.length ?? 0) > 0 ? { tags } : {}),
                ...((excludeTags?.length ?? 0) > 0 ? { excludeTags } : {}),
                ...(searchedTitle ? { title: searchedTitle } : {}),
                ...(searchedAuthor ? { createdBy: [searchedAuthor] } : {}),
            };
            if (Object.keys(filter).length > 0) {
                query.withFilter(filter);
            }
            const result = await query.query();
            // Check if THIS request was aborted (using captured signal, not current ref)
            if (currentSignal.aborted) {
                return;
            }
            setTotalItemsCount(result.totalCount);
            if (resetItems || isFirstPage) {
                setItems(result.items);
            }
            else {
                setItems((prevItems) => [...prevItems, ...result.items]);
            }
            // Handle initial load completion (use ref to avoid callback recreation)
            if (!initialLoadCompletedRef.current) {
                initialLoadCompletedRef.current = true;
                setInitialLoadCompleted(true);
                // When the user has no insights of their own, switch to the All tab
                if (tabId === tabsIds.my && result.totalCount === 0) {
                    setSelectedTabId(tabsIds.all);
                    // Fetch all insights immediately
                    const allQuery = backend
                        .workspace(workspaceId)
                        .insights()
                        .getInsightsQuery()
                        .withSize(ITEMS_PER_PAGE)
                        .withPage(0)
                        .withSorting(DEFAULT_INSIGHT_SORT);
                    const allFilter = {
                        ...((tags?.length ?? 0) > 0 ? { tags } : {}),
                        ...((excludeTags?.length ?? 0) > 0 ? { excludeTags } : {}),
                    };
                    if (Object.keys(allFilter).length > 0) {
                        allQuery.withFilter(allFilter);
                    }
                    const allResult = await allQuery.query();
                    if (!currentSignal.aborted) {
                        setItems(allResult.items);
                        setTotalItemsCount(allResult.totalCount);
                    }
                    return;
                }
            }
        }
        catch (error) {
            // Ignore abort errors
            if (error.name !== "AbortError") {
                console.error("Failed to fetch insights:", error);
            }
        }
        finally {
            // Only update loading state if this request wasn't superseded
            if (!currentSignal.aborted) {
                setIsLoading(false);
                setIsNextPageLoading(false);
            }
        }
    }, [backend, workspaceId, author, tabsIds, tags, excludeTags]);
    const loadNextPage = useCallback(() => {
        if (!hasNextPage || isNextPageLoading || isLoading) {
            return;
        }
        const nextPage = currentPage + 1;
        setCurrentPage(nextPage);
        void fetchItems({ page: nextPage, search, tabId: selectedTabId });
    }, [hasNextPage, isNextPageLoading, isLoading, currentPage, search, selectedTabId, fetchItems]);
    // eslint-disable-next-line react-hooks/exhaustive-deps
    const onSearch = useCallback(debounce((searchString) => {
        setCurrentPage(0);
        setSearch(searchString);
        void fetchItems({ page: 0, search: searchString, tabId: selectedTabId, resetItems: true });
    }, 500), [fetchItems, selectedTabId]);
    const onTabSelect = useCallback((tab) => {
        const { id: tabId } = tab;
        setCurrentPage(0);
        setSelectedTabId(tabId);
        void fetchItems({ page: 0, search, tabId, resetItems: true });
    }, [fetchItems, search]);
    const reset = useCallback(() => {
        if (abortControllerRef.current) {
            abortControllerRef.current.abort();
        }
        setItems([]);
        setTotalItemsCount(undefined);
        setIsLoading(false);
        setIsNextPageLoading(false);
        setCurrentPage(0);
        setSearch("");
    }, []);
    const shouldLoadNextPage = useCallback((lastItemIndex, itemsCount) => lastItemIndex >= itemsCount - 5, []);
    const loadInitialItems = useCallback(() => {
        void fetchItems({ page: 0, search: "", tabId: undefined, resetItems: true });
    }, [fetchItems]);
    const resetItems = useCallback(() => {
        void fetchItems({ page: 0, search: search, tabId: selectedTabId, resetItems: true });
    }, [fetchItems, search, selectedTabId]);
    return {
        items,
        totalItemsCount,
        isLoading,
        isNextPageLoading,
        initialLoadCompleted,
        currentPage,
        search,
        selectedTabId,
        hasNextPage,
        skeletonItemsCount,
        fetchItems,
        loadNextPage,
        onSearch,
        onTabSelect,
        reset,
        shouldLoadNextPage,
        loadInitialItems,
        resetItems,
    };
}
//# sourceMappingURL=useInsightPagedList.js.map