import { useEffect, useRef, useState } from "react";
import { loadPlaceholderInsertOptions, } from "../services/editService";
export function usePageModel(itemsRepository, pageItemDescriptor, parheliaSettings) {
    const [page, setPage] = useState();
    const [pageSkeleton, setPageSkeleton] = useState();
    const [insertOptions, setInsertOptions] = useState([]);
    const insertOptionsCache = useRef({});
    // 2) whenever the actual target page changes, reset skeleton, page and clear cache
    useEffect(() => {
        setPage(undefined);
        setPageSkeleton(undefined);
        insertOptionsCache.current = {};
        setInsertOptions([]);
    }, [pageItemDescriptor]);
    // 3) collect all placeholder-keys in a skeleton
    const collectPlaceholderKeys = (skeleton) => {
        const keys = [];
        const collect = (c) => {
            c.placeholders.forEach((ph) => {
                if (ph.editable)
                    keys.push(ph.key);
                ph.components.forEach(collect);
            });
        };
        collect(skeleton.rootComponent);
        return keys;
    };
    // 4) load only missing insertOptions
    useEffect(() => {
        const loadInsertOptions = async () => {
            if (!pageSkeleton)
                return;
            const allKeys = collectPlaceholderKeys(pageSkeleton);
            // find which keys we haven’t cached yet
            const missingKeys = allKeys.filter((k) => !(k in insertOptionsCache.current));
            if (missingKeys.length) {
                const newlyFetched = await loadPlaceholderInsertOptions(pageSkeleton.item, missingKeys);
                // stash them in our cache
                newlyFetched.forEach((opt) => {
                    insertOptionsCache.current[opt.key] = opt;
                });
            }
            // now build the full list in the original placeholder order
            const optionsInOrder = allKeys
                .map((k) => insertOptionsCache.current[k])
                .filter((opt) => !!opt);
            setInsertOptions(optionsInOrder);
        };
        loadInsertOptions();
    }, [pageSkeleton]);
    const updatePageModel = async () => {
        if (!itemsRepository) {
            return;
        }
        //const start = performance.now();
        const itemsToFetch = [];
        if (!pageSkeleton) {
            setPage(undefined);
            return;
        }
        // Prevent building page model if skeleton is from a different page than the current pageItemDescriptor.
        // This avoids showing incorrect "Shared" badges when the skeleton hasn't been updated yet for the current page.
        if (pageItemDescriptor && pageSkeleton.item.id !== pageItemDescriptor.id) {
            return;
        }
        itemsToFetch.push(pageSkeleton.item);
        const collectItems = (component) => {
            if (component.datasourceItem)
                itemsToFetch.push({
                    id: component.datasourceItem.id,
                    language: component.datasourceItem.language,
                    version: component.datasourceItem.version,
                });
            component.placeholders
                .flatMap((x) => x.components)
                .forEach((c) => collectItems(c));
            component.items.forEach((i) => itemsToFetch.push(i));
        };
        collectItems(pageSkeleton.rootComponent);
        // Use the hook's pageItemDescriptor if available, otherwise create from skeleton
        // This ensures we have the correct database property and other metadata
        const effectivePageItemDescriptor = pageItemDescriptor || {
            id: pageSkeleton.item.id,
            language: pageSkeleton.item.language,
            version: pageSkeleton.item.version,
            database: pageSkeleton.item.database,
        };
        // Pass pageItem to getItemsStubs so it can be included in the request for authorization
        // This is critical for limited preview users - datasources need pageItem context to be authorized
        let itemStubs;
        try {
            itemStubs = await itemsRepository.getItemsStubs(itemsToFetch, effectivePageItemDescriptor);
        }
        catch (e) {
            return;
        }
        const getItem = (descriptor) => itemStubs.find((x) => x.id === descriptor.id &&
            x.language === descriptor.language &&
            x.version === descriptor.version);
        const pageItem = await itemsRepository.getItem(pageSkeleton.item);
        if (!pageItem) {
            setPage(undefined);
            return;
        }
        const buildModel = (skeleton, parentPlaceholder) => {
            const datasourceItemTemp = skeleton.datasourceItem
                ? getItem(skeleton.datasourceItem)
                : undefined;
            const datasourceItem = skeleton.datasourceItem && datasourceItemTemp
                ? { ...skeleton.datasourceItem, ...datasourceItemTemp }
                : undefined;
            const name = skeleton.name || datasourceItem?.name || skeleton.type || "unknown";
            const mapItem = (x) => {
                const item = getItem(x);
                if (!item)
                    return null;
                return { ...x, ...item };
            };
            const items = skeleton.items.map(mapItem).filter((x) => x !== null);
            const placeholders = [];
            const component = {
                ...skeleton,
                name,
                icon: datasourceItem?.icon,
                datasourceItem,
                items,
                placeholders,
                // Prefer server-provided shared state to avoid client-side path
                // heuristics misclassifying page-local datasources as shared.
                isShared: skeleton.isShared ?? false,
                parentPlaceholder,
                editable: skeleton.editable ?? true,
                type: skeleton.type || datasourceItem?.templateName || name,
                typeId: skeleton.typeId || datasourceItem?.templateId || "",
                canBeMoved: !datasourceItem ||
                    datasourceItem?.id !== parentPlaceholder?.parentComponent?.id,
            };
            component.placeholders = skeleton.placeholders.map((x) => {
                const options = insertOptions.find((y) => y.key === x.key);
                const editable = x.editable ?? options?.editable ?? false;
                const insOpts = options?.insertOptions ?? [];
                const placeholder = {
                    ...x,
                    components: [],
                    canSynchronize: false,
                    parentComponent: component,
                    insertOptions: insOpts,
                    editable,
                };
                placeholder.components = x.components
                    .map((y) => buildModel(y, placeholder))
                    .filter((x) => x !== undefined);
                return placeholder;
            });
            return component;
        };
        const rootComponent = buildModel(pageSkeleton.rootComponent);
        if (!rootComponent) {
            setPage(undefined);
            return;
        }
        const page = {
            item: pageItem,
            rootComponent,
            //    revision: itemsRepository.revision,
            editRevision: pageSkeleton.editRevision,
        };
        setPage(page);
    };
    useEffect(() => {
        updatePageModel();
    }, [pageSkeleton, insertOptions]);
    return {
        setPageSkeleton,
        page,
    };
}
//# sourceMappingURL=pageModelBuilder.js.map