import { createElement as _createElement } from "react";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useReducer, useState, useMemo, useContext, useRef, useEffect, memo } from 'react';
import { createPortal } from 'react-dom';
import { createUID, windowIsAvailable } from '../../utils';
import '../../init';
import { useConfiguration } from '../../hooks';
import PreviewPanel from './PreviewPanel';
import { PreviewContext, PreviewManagerContext } from './Contexts';
const reducer = (previews, payload) => {
    switch (payload.type) {
        case 'create':
            // Stub for multiple preview support
            // return [...previews, payload.preview as unknown as PreviewObject<object>];
            return [payload.preview];
        case 'update':
            return previews.map(preview => preview.id === payload.id
                ? {
                    ...preview,
                    props: { ...preview.props, ...payload.props },
                    options: {
                        ...preview.options,
                        ...payload.options,
                        previewProps: {
                            ...preview.options?.previewProps,
                            ...payload.options?.previewProps
                        }
                    }
                }
                : preview);
        case 'unmount':
            return previews.filter(preview => preview.id !== payload.id);
        default:
            return previews;
    }
};
const WrappedPreview = memo(({ Component, props, options, previewStateSetter, previewTriggerRef, methods }) => {
    const optionsRef = useRef(options);
    optionsRef.current = options;
    // This state change is required to transition the case preview in.
    const [open, setOpen] = useState(false);
    const openRef = useRef(false);
    const cleanupPreview = () => {
        setOpen(false);
        openRef.current = false;
        previewStateSetter(false);
        optionsRef.current?.previewProps.onAfterClose?.();
        methods.unmountPreview();
    };
    useEffect(() => {
        setOpen(true);
        openRef.current = true;
        previewStateSetter(true);
        return () => {
            // Guard with openRef so we don't double-fire if already closed via the close button.
            if (openRef.current) {
                optionsRef.current?.previewProps.onBeforeClose?.();
                cleanupPreview();
            }
        };
    }, []);
    return (_jsx(PreviewContext.Provider
    // eslint-disable-next-line react/jsx-no-constructed-context-values
    , { 
        // eslint-disable-next-line react/jsx-no-constructed-context-values
        value: {
            initialized: true,
            previewTriggerRef,
            ...methods
        }, children: _jsx(PreviewPanel, { open: open, ...options?.previewProps, onAfterClose: () => {
                cleanupPreview();
            }, children: _jsx(Component, { ...props }) }) }));
});
const PreviewManager = ({ children }) => {
    const [previews, dispatch] = useReducer(reducer, []);
    const [previewActive, setPreviewActive] = useState(false);
    const previewTriggerRef = useRef(null);
    const { portalTarget } = useConfiguration();
    const providerValue = useMemo(() => ({
        previewActive,
        setPreviewActive,
        createPreview: (Component, props, options) => {
            const id = createUID();
            const methods = {
                updatePreview: (updatedProps, updatedOptions) => {
                    dispatch({
                        type: 'update',
                        id,
                        props: updatedProps,
                        options: updatedOptions
                    });
                },
                unmountPreview: () => {
                    dispatch({ type: 'unmount', id });
                }
            };
            dispatch({
                type: 'create',
                preview: {
                    id,
                    Component,
                    methods,
                    props: (props ?? {}),
                    options
                }
            });
            return methods;
        },
        PreviewContext,
        initialized: true
    }), [previewActive]);
    const context = windowIsAvailable
        ? window.cosmos.previewManagerContext ?? PreviewManagerContext
        : PreviewManagerContext;
    const priorCtx = useContext(context);
    // Don't create additional Preview managers.
    if (priorCtx.initialized)
        return _jsx(context.Provider, { value: priorCtx, children: children });
    const previewPortal = portalTarget && previews.length > 0
        ? createPortal(previews.map(preview => (_createElement(WrappedPreview, { ...preview, key: preview.id, previewStateSetter: setPreviewActive, previewTriggerRef: previewTriggerRef }))), portalTarget)
        : null;
    return (_jsx(context.Provider, { value: providerValue, children: _jsxs(PreviewContext.Provider, { value: { initialized: false, previewTriggerRef }, children: [children, previewPortal] }) }));
};
export default PreviewManager;
//# sourceMappingURL=PreviewManager.js.map