import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { createContext, useContext, useMemo, useEffect, useState } from 'react';
import { createPortal } from 'react-dom';
import { ThemeProvider, StyleSheetManager } from 'styled-components';
import '../../init';
import { GlobalStyle } from '../../styles';
import { ThemeMachine, BaseThemeMachine } from '../../theme';
import { createTranslationPack, DefaultTranslation, direction as directionOfLocale } from '../../i18n';
import { documentIsAvailable, navigatorIsAvailable, windowIsAvailable } from '../../utils';
import pkg from '../../../package.json';
import useElement from '../../hooks/useElement';
import './connected-watcher';
const defaultLocale = navigatorIsAvailable ? navigator.language : 'en';
export const ConfigurationContext = createContext({
    locale: defaultLocale,
    direction: directionOfLocale(defaultLocale),
    translations: DefaultTranslation,
    themeMachine: BaseThemeMachine,
    styleSheetTarget: documentIsAvailable ? document.head : undefined,
    portalTarget: documentIsAvailable ? document.body : undefined,
    loadedRef: { current: false },
    renderNativeControls: false,
    testIds: true,
    mountedStyleSheetManagers: [],
    initialized: false
});
const legacyMetaKey = Symbol.for('@pega/cosmos-react-core.metadata');
const mountedConfigs = new Set();
const instance = {
    version: pkg.version,
    mountedConfigs: [],
    mountOrder: [],
    mountCount: {}
};
const mountConfig = (sym) => {
    mountedConfigs.add(sym);
    instance.mountedConfigs = [...mountedConfigs].map(i => i.description ?? 'Unknown');
    const description = sym.description ?? 'Unknown';
    instance.mountOrder.push(description);
    if (!(description in instance.mountCount)) {
        instance.mountCount[description] = 0;
    }
    instance.mountCount[description] += 1;
};
const unmountConfig = (sym) => {
    mountedConfigs.delete(sym);
    instance.mountedConfigs = [...mountedConfigs].map(i => i.description ?? 'Unknown');
};
if (windowIsAvailable) {
    if (!window.cosmos.instances) {
        window.cosmos.instances = [];
    }
    window.cosmos.instances.push(instance);
    if (Array.isArray(window[legacyMetaKey])) {
        window.cosmos.instances.push(...window[legacyMetaKey]);
        delete window[legacyMetaKey];
    }
    if (!window[legacyMetaKey]) {
        window[legacyMetaKey] = {
            push: inst => {
                window.cosmos.instances?.push(inst);
            }
        };
    }
}
const Configuration = ({ children, locale, direction, translations: customTranslations, theme, disableDefaultFontLoading, styleSheets: styleSheetURLs, styleSheetTarget, portalTarget, renderNativeControls, testIds, id }) => {
    const context = windowIsAvailable
        ? window.cosmos.configurationContext ?? ConfigurationContext
        : ConfigurationContext;
    const ctx = useContext(context);
    const themeMachine = theme
        ? new ThemeMachine({ theme, parent: ctx.themeMachine })
        : ctx.themeMachine;
    const translations = useMemo(() => createTranslationPack({ ...ctx.translations, ...customTranslations }), [ctx.translations, customTranslations]);
    const [wrapperEl, setWrapperEl] = useElement();
    const [connectedWatcherEl, setConnectedWatcherEl] = useElement();
    // State tracking if the DOM nodes are connected. Only used to trigger rerenders when connected state changes.
    const [, setConnected] = useState(null);
    useEffect(() => {
        if (!connectedWatcherEl)
            return;
        const connectDisconnectListener = () => {
            setConnected(connectedWatcherEl.isConnected);
        };
        connectedWatcherEl.addEventListener('connect-disconnect', connectDisconnectListener);
        return () => {
            connectedWatcherEl.removeEventListener('connect-disconnect', connectDisconnectListener);
        };
    }, [connectedWatcherEl]);
    // Determine valid style sheet and portal target with ShadowDOM handling.
    const [resolvedStyleSheetTarget, resolvedPortalTarget] = useMemo(() => {
        // When rendering on the server, or before the wrapper is in the DOM, just bail.
        if (!documentIsAvailable || !wrapperEl?.isConnected)
            return [undefined, undefined];
        const rootNode = wrapperEl.getRootNode();
        // When within the ShadowDOM, the default target is the ShadowRoot, otherwise default to head/body element.
        const defaultStyleSheetTarget = rootNode instanceof ShadowRoot ? rootNode : document.head;
        const defaultPortalTarget = rootNode instanceof ShadowRoot ? rootNode : document.body;
        // Currently passed prop or previous context value
        const requestedStyleSheetTarget = styleSheetTarget ?? ctx.styleSheetTarget;
        const requestedPortalTarget = portalTarget ?? ctx.portalTarget;
        // If the "requested" target is within the root node, it is valid, so use that, otherwise fallback to the default.
        return [
            rootNode.contains(requestedStyleSheetTarget ?? null)
                ? requestedStyleSheetTarget
                : defaultStyleSheetTarget,
            rootNode.contains(requestedPortalTarget ?? null) ? requestedPortalTarget : defaultPortalTarget
        ];
    }, [
        wrapperEl,
        wrapperEl?.isConnected,
        styleSheetTarget,
        portalTarget,
        ctx.styleSheetTarget,
        ctx.portalTarget
    ]);
    // Load global fonts and styles if this configuration instance is...
    const shouldInitialize = useMemo(() => 
    // the first configuration instance or...
    !ctx.initialized ||
        // is not within the same root node as the previous configuration instance.
        !!(wrapperEl && wrapperEl.getRootNode() !== ctx.styleSheetTarget?.getRootNode()), [ctx.initialized, wrapperEl]);
    // Check if this StyleSheetManager is mounted above this Configuration.
    const stylesheetManagerMounted = useMemo(() => !!ctx.mountedStyleSheetManagers?.includes(StyleSheetManager), [ctx.mountedStyleSheetManagers]);
    useEffect(() => {
        const sym = Symbol(id);
        mountConfig(sym);
        return () => {
            unmountConfig(sym);
        };
    }, [id]);
    const wrappedChildren = shouldInitialize ? (_jsxs(_Fragment, { children: [!disableDefaultFontLoading &&
                resolvedStyleSheetTarget &&
                createPortal(_jsx("link", { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,400..700;1,400..700&family=Inter:wght@400..700&display=swap', "data-cosmos-global-style": true }), resolvedStyleSheetTarget), _jsx(GlobalStyle, {}), children] })) : (_jsx(_Fragment, { children: children }));
    const styledWrappedChildren = stylesheetManagerMounted ? (wrappedChildren) : (_jsx(StyleSheetManager, { disableVendorPrefixes: true, target: 
        // Target must be undefined in a JSDOM environment due to Styled Components server mode handling.
        navigatorIsAvailable &&
            resolvedStyleSheetTarget?.isConnected &&
            !navigator.userAgent.includes('jsdom')
            ? resolvedStyleSheetTarget
            : undefined, children: wrappedChildren }));
    return (_jsxs("div", { "data-config-root": true, 
        // Need to use inline styles because the StyleSheetManager is configured within this div.
        style: { display: 'contents' }, ref: setWrapperEl, children: [_jsx(context.Provider
            // eslint-disable-next-line react/jsx-no-constructed-context-values
            , { 
                // eslint-disable-next-line react/jsx-no-constructed-context-values
                value: {
                    locale: locale ?? ctx.locale,
                    direction: direction ?? (locale !== undefined ? directionOfLocale(locale) : ctx.direction),
                    translations,
                    themeMachine,
                    styleSheetTarget: resolvedStyleSheetTarget,
                    portalTarget: resolvedPortalTarget,
                    loadedRef: ctx.loadedRef,
                    renderNativeControls: renderNativeControls ?? ctx.renderNativeControls,
                    testIds: testIds ?? ctx.testIds,
                    mountedStyleSheetManagers: stylesheetManagerMounted
                        ? ctx.mountedStyleSheetManagers
                        : [...(ctx.mountedStyleSheetManagers ?? []), StyleSheetManager],
                    initialized: true
                }, children: _jsxs(ThemeProvider, { theme: themeMachine.theme, children: [styleSheetURLs &&
                            resolvedStyleSheetTarget &&
                            createPortal(styleSheetURLs.map(url => (_jsx("link", { rel: 'stylesheet', href: url, "data-cosmos-global-style": true }, url))), resolvedStyleSheetTarget), styledWrappedChildren] }) }), _jsx("pega-connected-watcher", { ref: setConnectedWatcherEl, style: { display: 'none' } })] }));
};
export default Configuration;
//# sourceMappingURL=Configuration.js.map