"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppRender = exports.CommonAppRender = exports.generateSlotMetaMap = exports.Trace = exports.getComponentChildren = void 0;
const tslib_1 = require("tslib");
const React = tslib_1.__importStar(require("react"));
const NodeRenderer_1 = require("./NodeRenderer");
const common_1 = require("../utils/common");
const mobx_react_lite_1 = require("mobx-react-lite");
const error_1 = require("../utils/error");
const router_1 = require("../router");
const utils_1 = require("../utils");
const lodash_es_1 = require("lodash-es");
function checkDoNotRenderSlot(componentSchema, renderSlot, rootNode) {
    // 判断是否为 slot
    return (0, common_1.isSlot)(componentSchema) && !(renderSlot || rootNode);
}
function getComponentChildren(component, context) {
    const { items = [] } = component;
    if (!items.length) {
        return [];
    }
    const list = items.sort((a, b) => { var _a, _b; return (((_a = a.extra) === null || _a === void 0 ? void 0 : _a.xIndex) || 0) - (((_b = b.extra) === null || _b === void 0 ? void 0 : _b.xIndex) || 0); });
    const { virtualFields, codeContext, scopeContext, forContext, injectContext, dataContext, updateContext } = context;
    return list.map((schema) => {
        return getRenderList({
            key: schema.id,
            componentSchema: schema,
            rootNode: false,
            renderSlot: false,
            virtualFields,
            codeContext,
            scopeContext,
            forContext,
            injectContext,
            dataContext,
            updateContext,
        });
    });
}
exports.getComponentChildren = getComponentChildren;
exports.Trace = (0, mobx_react_lite_1.observer)(function Trace({ id }) {
    const scopeContext = React.useContext(NodeRenderer_1.ScopeContext);
    console.log('id', id, (0, lodash_es_1.get)(scopeContext, id));
    return null;
});
function useEqualValue(value) {
    const valueRef = React.useRef(value);
    return React.useMemo(() => {
        if (!(0, lodash_es_1.isEqual)(value, valueRef.current)) {
            valueRef.current = value;
        }
        return valueRef.current;
    }, [value]);
}
function HOCWtichRegistData(props) {
    var _a, _b, _c;
    const { id, data: _data, componentSchema, renderSlot, slotConfig = {}, codeContext, forContext: _forContext, scopeContext, injectContext, dataContext, virtualFields, } = props;
    const data = useEqualValue(_data);
    const isMultiSlotInstance = ((_a = slotConfig === null || slotConfig === void 0 ? void 0 : slotConfig['x-slot-directives']) === null || _a === void 0 ? void 0 : _a._index) && ((_b = slotConfig === null || slotConfig === void 0 ? void 0 : slotConfig['x-slot-directives']) === null || _b === void 0 ? void 0 : _b.for);
    const indexKey = (_c = slotConfig === null || slotConfig === void 0 ? void 0 : slotConfig['x-slot-directives']) === null || _c === void 0 ? void 0 : _c._index;
    const isInComposite = !!codeContext.$WEAPPS_COMP;
    const widgetsData = !isInComposite ? codeContext.$page.widgets[id] : codeContext.$WEAPPS_COMP.widgets[id];
    let forContext = React.useMemo(() => {
        const { forIndexes = [], forStack = [] } = _forContext;
        return isMultiSlotInstance && data[indexKey] !== undefined
            ? Object.assign(Object.assign({}, _forContext), { [id]: data, forIndexes: forIndexes.concat(data[indexKey]), forStack: [
                    ...forStack,
                    {
                        currentIndex: data[indexKey],
                        currentItem: data,
                    },
                ] }) : _forContext;
    }, [data[indexKey]]);
    const { forIndexes = [] } = forContext;
    const currentWidget = Array.isArray(widgetsData)
        ? widgetsData.length
            ? (0, lodash_es_1.get)(widgetsData, forIndexes)
            : undefined
        : widgetsData;
    const [componentId, key] = id.split('.');
    React.useEffect(() => {
        if (!currentWidget) {
            // debugger;
            return;
        }
        currentWidget._scope.scopeContext = data;
    }, [currentWidget, data]);
    const memoScopeContext = React.useMemo(() => {
        return Object.assign(Object.assign({}, scopeContext), { [componentId]: {
                [key]: data,
            } });
    }, [componentId, key, data]);
    return currentWidget ? (React.createElement(router_1.InjectContext.Provider, { value: injectContext },
        React.createElement(NodeRenderer_1.ScopeContext.Provider, { value: memoScopeContext },
            React.createElement(NodeRenderer_1.DataContext.Provider, { value: dataContext },
                React.createElement(NodeRenderer_1.ForContext.Provider, { value: forContext },
                    React.createElement(exports.AppRender, { componentSchema: componentSchema, renderSlot: renderSlot, virtualFields: virtualFields, codeContext: codeContext })))))) : null;
}
function generateSlotMetaMap(componentSchema, context, options) {
    const { items = [] } = componentSchema;
    const { scopeContext, codeContext, virtualFields, injectContext } = context;
    const slots = {};
    // eslint-disable-next-line guard-for-in
    for (const child of items) {
        // TODO 做到不依赖组件 id
        const key = child.id;
        if ((0, common_1.isSlot)(child)) {
            const slotId = `${componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.id}.${key}`;
            if ((injectContext.checkVisible || utils_1.checkVisible)({ id: slotId })) {
                const { isScopeSlot: isHOC, config } = (0, common_1.getScopeSlotMeta)(componentSchema, key, injectContext);
                slots[key] = {
                    type: isHOC ? 'HOC' : 'ELEMENT',
                    node: isHOC
                        ? function ({ forContext, dataContext }) {
                            return function ScopedSlot(props) {
                                return (React.createElement(HOCWtichRegistData, { id: slotId, data: props, componentSchema: child, renderSlot: options.renderSlot, slotConfig: config, codeContext: codeContext, forContext: forContext, dataContext: dataContext, scopeContext: scopeContext, injectContext: injectContext, virtualFields: virtualFields }));
                            };
                        }
                        : ({ forContext, dataContext }) => {
                            return (React.createElement(router_1.InjectContext.Provider, { value: injectContext },
                                React.createElement(NodeRenderer_1.ScopeContext.Provider, { value: scopeContext },
                                    React.createElement(NodeRenderer_1.DataContext.Provider, { value: dataContext },
                                        React.createElement(NodeRenderer_1.ForContext.Provider, { value: forContext },
                                            React.createElement(exports.AppRender, { componentSchema: child, renderSlot: options === null || options === void 0 ? void 0 : options.renderSlot, virtualFields: virtualFields, codeContext: codeContext }))))));
                        },
                };
            }
        }
    }
    return slots;
}
exports.generateSlotMetaMap = generateSlotMetaMap;
function getRenderList(props) {
    var _a;
    const { key, virtualFields, componentSchema, renderSlot, rootNode = true, codeContext, scopeContext, forContext = {}, injectContext = {}, dataContext, updateContext, } = props;
    const { genericComp = {} } = componentSchema.extra || {};
    // 判断是否为 slot
    if (checkDoNotRenderSlot(componentSchema, renderSlot, rootNode)) {
        return null;
    }
    if (componentSchema.module && componentSchema.component) {
        const sourceKey = `${componentSchema.module}:${componentSchema.component}`;
        const Field = virtualFields[sourceKey];
        if (!Field) {
            return React.createElement(error_1.ComponentNotFound, { key: key, module: componentSchema.module, component: componentSchema.component });
        }
    }
    return (0, NodeRenderer_1.getComponentRenderList)({
        key,
        componentSchema,
        rootNode,
        emitEvents: ((_a = componentSchema.extra) === null || _a === void 0 ? void 0 : _a.emitEvents) || [],
        renderSlot,
        virtualFields,
        codeContext,
        scopeContext,
        forContext,
        dataContext,
        updateContext,
        injectContext,
        genericComp,
    });
}
// CommonAppRender.whyDidYouRender = true;
function CommonAppRender(props) {
    var _a, _b, _c, _d;
    // trace(true);
    const { className, componentSchema } = props;
    //  wrapperClass;
    const preClassNameList = React.useRef([]);
    const { items = [] } = componentSchema;
    const currentInjectClassNameList = ((_c = (_b = (_a = className === null || className === void 0 ? void 0 : className.split) === null || _a === void 0 ? void 0 : _a.call(className, /\s/)) === null || _b === void 0 ? void 0 : _b.filter) === null || _c === void 0 ? void 0 : _c.call(_b, (item) => !!item)) || [];
    const containerEl = items[0];
    if (className && containerEl) {
        if (!containerEl.attributes) {
            containerEl.attributes = {};
        }
        let classNameList = (((_d = containerEl.attributes) === null || _d === void 0 ? void 0 : _d.class) || '').split(/\s/).filter((item) => !!item);
        // 先替换掉先前计算出来的className部分
        if (preClassNameList.current.length) {
            const map = preClassNameList.current.reduce((map, item) => {
                map[item] = true;
                return map;
            }, {});
            classNameList = classNameList.filter((item) => !map[item]);
        }
        containerEl.attributes.class = Array.from(new Set(classNameList.concat(currentInjectClassNameList))).join(' ');
    }
    preClassNameList.current = currentInjectClassNameList;
    return getRenderList(Object.assign(Object.assign({}, props), { 
        // dataContext: {},
        // scopeContext: {},
        // forContext: {},
        // injectContext: {},
        dataContext: React.useContext(NodeRenderer_1.DataContext), scopeContext: React.useContext(NodeRenderer_1.ScopeContext), forContext: React.useContext(NodeRenderer_1.ForContext), injectContext: React.useContext(router_1.InjectContext) }));
}
exports.CommonAppRender = CommonAppRender;
exports.AppRender = (0, mobx_react_lite_1.observer)(CommonAppRender);
//# sourceMappingURL=RenderWrapper.js.map