"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getShadowRoot = getShadowRoot;
const tslib_1 = require("tslib");
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const react_1 = tslib_1.__importStar(require("react"));
const react_dom_1 = tslib_1.__importDefault(require("react-dom"));
const ide_components_1 = require("@opensumi/ide-components");
const ide_core_browser_1 = require("@opensumi/ide-core-browser");
const ide_core_common_1 = require("@opensumi/ide-core-common");
const ide_theme_1 = require("@opensumi/ide-theme");
const extension_service_1 = require("../common/extension.service");
const pkgJson = require('../../package.json');
const ShadowContent = ({ root, children }) => react_dom_1.default.createPortal(children, root);
function cloneNode(head) {
    return head.cloneNode(true);
}
/**
 * 由于经过 clone 以后，实际 Shadow DOM 中 head 与原始 proxiedHead 不是同一份引用
 * 插件中可能存在后置动态插入 style 的行为，此时只会获取到 proxiedHead
 * 所以这里观察原始 proxiedHead 的 DOM childList 变化
 * 当收到 mutations 时说明 head 标签被修改，将新插入的 style 节点 clone 一份到实际的 head 中
 * 删除节点同理
 */
function useMutationObserver(from, target) {
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                if (mutation.addedNodes.length > 0) {
                    for (const addedNode of Array.from(mutation.addedNodes)) {
                        // TODO: 加入真正的 typing
                        target.appendChild(addedNode.cloneNode(true));
                    }
                }
                if (mutation.removedNodes.length > 0) {
                    for (const removedNode of Array.from(mutation.removedNodes)) {
                        if (target.contains(removedNode)) {
                            target.removeChild(removedNode);
                        }
                    }
                }
            }
        }
    });
    observer.observe(from, {
        // 表示监听子元素列表变化
        childList: true,
        subtree: true,
    });
    return {
        dispose: () => {
            observer.disconnect();
        },
    };
}
const packageName = '@opensumi/ide-components';
function getCDNHref(filePath, version, cdnType = 'alipay') {
    return (0, ide_core_browser_1.getCDNHref)(packageName, filePath, version, cdnType);
}
function getStyleSheet(href) {
    const link = document.createElement('link');
    link.setAttribute('href', href);
    link.setAttribute('rel', 'stylesheet');
    return link;
}
const ShadowRoot = ({ id, extensionId, children, proxiedHead, cdnType, styleSheet, }) => {
    const shadowRootRef = (0, react_1.useRef)(null);
    const [shadowRoot, setShadowRoot] = react_1.default.useState(null);
    const viewExtensionService = (0, ide_core_browser_1.useInjectable)(extension_service_1.AbstractViewExtProcessService);
    const themeService = (0, ide_core_browser_1.useInjectable)(ide_theme_1.IThemeService);
    const iconService = (0, ide_core_browser_1.useInjectable)(ide_theme_1.IIconService);
    const productIconService = (0, ide_core_browser_1.useInjectable)(ide_theme_1.IProductIconService);
    const [themeType, setThemeType] = (0, react_1.useState)(null);
    (0, react_1.useEffect)(() => {
        var _a, _b;
        const disposables = new ide_core_browser_1.DisposableCollection();
        if (shadowRootRef.current) {
            const shadowRootElement = shadowRootRef.current.attachShadow({ mode: 'open' });
            if (proxiedHead) {
                if (styleSheet) {
                    proxiedHead.appendChild(getStyleSheet(styleSheet.componentUri));
                    proxiedHead.appendChild(getStyleSheet(styleSheet.iconfontUri));
                }
                else {
                    proxiedHead.appendChild(getStyleSheet(getCDNHref('dist/index.css', pkgJson.version, cdnType)));
                    proxiedHead.appendChild(getStyleSheet(getCDNHref('lib/icon/iconfont/iconfont.css', pkgJson.version, cdnType)));
                }
                // 如果是一个插件注册了多个视图，节点需要被 clone 才能生效，否则第一个视图 appendChild 之后节点就没了
                const newHead = cloneNode(proxiedHead);
                disposables.push(useMutationObserver(proxiedHead, newHead));
                // 注册 icon 相关的样式
                const iconStyle = document.createElement('style');
                iconStyle.id = 'icon-style';
                iconStyle.innerHTML = (_a = iconService.currentTheme) === null || _a === void 0 ? void 0 : _a.styleSheetContent;
                newHead.appendChild(iconStyle);
                // 注册 producticon theme
                const productIconStyle = document.createElement('style');
                productIconStyle.id = ide_theme_1.PRODUCT_ICON_STYLE_ID;
                productIconStyle.innerHTML = ((_b = productIconService.currentTheme) === null || _b === void 0 ? void 0 : _b.styleSheetContent) || '';
                newHead.appendChild(productIconStyle);
                disposables.pushAll([
                    iconService.onThemeChange((e) => {
                        iconStyle.innerHTML = e.styleSheetContent;
                    }),
                ]);
                shadowRootElement.appendChild(newHead);
                const portalRoot = viewExtensionService.getPortalShadowRoot(extensionId);
                if (portalRoot) {
                    portalRoot.appendChild(proxiedHead);
                }
            }
            if (!shadowRoot) {
                setShadowRoot(shadowRootElement);
            }
            themeService.getCurrentTheme().then((res) => setThemeType(res.type));
            disposables.push(themeService.onThemeChange((e) => {
                if (e.type && e.type !== themeType) {
                    setThemeType(e.type);
                }
            }));
            return disposables.dispose.bind(disposables);
        }
    }, []);
    return (react_1.default.createElement("div", { id: id, style: { width: '100%', height: '100%' }, ref: shadowRootRef }, shadowRoot && (react_1.default.createElement(ShadowContent, { root: shadowRoot },
        react_1.default.createElement("div", { className: (0, classnames_1.default)((0, ide_theme_1.getThemeTypeSelector)(themeType), 'shadow-context-wrapper', 'show-file-icons'), style: { width: '100%', height: '100%' } }, children)))));
};
function getShadowRoot(panel, extension, props, id, proxiedHead, type, extensionBrowserStyleSheet) {
    const Component = panel;
    const { getIcon } = react_1.default.useContext(ide_components_1.IconContext);
    const labelService = (0, ide_core_browser_1.useInjectable)(ide_core_browser_1.LabelService);
    const getResourceIcon = (0, react_1.useCallback)((uri, options) => labelService.getIcon(ide_core_common_1.URI.parse(uri), options), []);
    return (react_1.default.createElement(ide_components_1.ComponentContextProvider, { value: { getIcon, localize: ide_core_common_1.localize, getResourceIcon } },
        react_1.default.createElement(ShadowRoot, { id: `${extension.id}-${id}`, extensionId: extension.id, proxiedHead: proxiedHead, cdnType: type, styleSheet: extensionBrowserStyleSheet },
            react_1.default.createElement(Component, { ...props }))));
}
//# sourceMappingURL=shadowRoot.js.map