"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getForIndexes = exports.CompRenderer = exports.getComponentRenderList = exports.DataContext = exports.ScopeContext = exports.ForContext = void 0;
var tslib_1 = require("tslib");
var React = tslib_1.__importStar(require("react"));
var mobx_react_lite_1 = require("mobx-react-lite");
var utils_1 = require("../utils");
var lodash_es_1 = require("lodash-es");
var RenderWrapper_1 = require("./RenderWrapper");
var router_1 = require("../router");
var error_1 = require("../utils/error");
var cals_1 = require("@cloudbase/cals");
var mobx_1 = require("mobx");
exports.ForContext = React.createContext({});
exports.ScopeContext = React.createContext({});
exports.DataContext = React.createContext({});
function getSafeComponentProps(_a) {
    var style = _a.style, classNameList = _a.classNameList;
    var componentProps = {};
    if (classNameList.length) {
        componentProps.className = classNameList.join(' ');
    }
    if (style && Object.keys(style).length) {
        componentProps.style = style;
    }
    return componentProps;
}
// TODO: 需要不断移除 dataBinds(style/classList)
function getBindData(_a) {
    var _b;
    var widgetData = _a.widgetData, forItems = _a.forItems, scopeContext = _a.scopeContext, codeContext = _a.codeContext, _c = _a.commonStyle, commonStyle = _c === void 0 ? {} : _c, _d = _a.classNameList, classNameList = _d === void 0 ? [] : _d;
    // bindData
    if (Array.isArray(widgetData)) {
        widgetData =
            forItems.forIndexes === void 0 || widgetData.length === 0
                ? {}
                : (0, lodash_es_1.get)(widgetData, getForIndexes(forItems, widgetData));
    }
    widgetData = widgetData || {};
    var fieldData = tslib_1.__assign({}, widgetData);
    var isRootNode = widgetData && !widgetData.parent;
    var isInComposite = !!codeContext.$WEAPPS_COMP;
    // 再次计算 scope value
    for (var key in fieldData) {
        if (Object.prototype.hasOwnProperty.call(fieldData, key)) {
            var value = fieldData[key];
            if (value && value.__type === 'scopedValue') {
                try {
                    fieldData[key] = value.getValue(scopeContext || {});
                }
                catch (e) {
                    console.warn("Error computing data bind '".concat(key, "' error:"), e);
                    fieldData[key] = '';
                }
            }
        }
    }
    // bindStyle
    var bindStyle = fieldData.style || {};
    // 复合组件第一层需要将最外层样式 style 挂到节点上
    var cssStyle = commonStyle || {};
    if (isInComposite && isRootNode) {
        bindStyle = tslib_1.__assign(tslib_1.__assign({}, bindStyle), (((_b = codeContext.$WEAPPS_COMP.props) === null || _b === void 0 ? void 0 : _b.style) || {}));
    }
    var finalStyle = getFinalStyle(cssStyle, bindStyle);
    // bindClassList
    var bindClassList = fieldData.classList || [];
    var finalClassNameList = getFinalClassNameList(classNameList, bindClassList);
    // 当前在复合组件中，且当前节点为根节点
    if (isInComposite && isRootNode) {
        if (widgetData.ownerWidget) {
            Object.keys(widgetData.ownerWidget).forEach(function (propName) {
                if (propName === 'role' || ['aria-', 'data-'].some(function (prefix) { return propName.startsWith(prefix); })) {
                    widgetData[propName] = widgetData.ownerWidget[propName];
                }
            });
        }
    }
    // 防止渲染时 data 的 style 与实际的 style 冲突
    delete fieldData.style;
    return {
        fieldData: fieldData,
        finalStyle: finalStyle,
        finalClassNameList: Array.from(new Set(finalClassNameList)),
    };
}
var _FOR_ERROR_CACHE_MAP = {};
function getForList(compId, dataBinds, parentForItems, dataContext) {
    /**
     * For循环渲染
     * @important
     * @default undfined // 代表没有进行for循环绑定
     */
    var forList = undefined;
    try {
        // 绑定了 for 变量，计算值最差应该是空数组
        // 没有绑定，那就是 undefined
        clearTimeout(_FOR_ERROR_CACHE_MAP[compId]);
        var list_1 = (dataBinds === null || dataBinds === void 0 ? void 0 : dataBinds._waFor) ? dataBinds._waFor(parentForItems, undefined, dataContext) || [] : undefined;
        // 绑定了for 并且计算了值，但是不是数组类型，应该进行兜底
        if (list_1 && !Array.isArray(list_1)) {
            _FOR_ERROR_CACHE_MAP[compId] = setTimeout(function () {
                console.warn("".concat(compId, "\u5FAA\u73AF\u7ED1\u5B9A\u975E\u6570\u7EC4\u503C\uFF1A"), list_1);
            }, 1000);
            list_1 = [];
        }
        forList = list_1;
    }
    catch (e) {
        // 计算值出错则使用空数组兜底
        _FOR_ERROR_CACHE_MAP[compId] = setTimeout(function () {
            console.warn("".concat(compId, "\u5FAA\u73AF\u7ED1\u5B9A\u9519\u8BEF"), e);
        }, 1000);
        forList = [];
    }
    if (forList) {
        if (!Array.isArray(forList)) {
            console.warn("".concat(compId, "\u5FAA\u73AF\u7ED1\u5B9A\u975E\u6570\u7EC4\u503C\uFF1A"), forList);
            forList = [];
        }
    }
    return forList;
}
// FieldWrapper 依赖 currentWidgets scope 因此需要添加observer
var FieldWrapper = (0, mobx_react_lite_1.observer)(_FieldWrapper);
function _FieldWrapper(_a) {
    var _b, _c, _d, _e;
    var Field = _a.Field, componentSchema = _a.componentSchema, id = _a.id, data = _a.data, _f = _a.style, style = _f === void 0 ? {} : _f, _g = _a.className, className = _g === void 0 ? '' : _g, events = _a.events, compositeParent = _a.compositeParent, context = _a.context, updateContext = _a.updateContext, _h = _a.renderSlot, renderSlot = _h === void 0 ? false : _h;
    var forContext = context.forContext, forIndexes = context.forIndexes, widgetsData = context.widgetsData, codeContext = context.codeContext, 
    //  dataContext,
    virtualFields = context.virtualFields;
    var injectContext = React.useContext(router_1.InjectContext);
    var scopeContext = React.useContext(exports.ScopeContext);
    var _dataContext = React.useContext(exports.DataContext);
    var indexRef = React.useRef();
    var typeRef = React.useRef();
    var instanceRef = React.useRef();
    var _j = tslib_1.__read(React.useState(0), 2), _ = _j[0], forceUpate = _j[1];
    var isInComposite = !!codeContext.$WEAPPS_COMP;
    var isDataContainer = (_c = (_b = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.extra) === null || _b === void 0 ? void 0 : _b.compConfig) === null || _c === void 0 ? void 0 : _c.isDataContainer;
    var currentWidget = Array.isArray(widgetsData) ? (0, lodash_es_1.get)(widgetsData, forIndexes) : widgetsData;
    // context 变化强刷一次children，同时把 currentWidget._scope?.dataContext  添加到 observer 中
    var dispose = React.useMemo(function () {
        return (0, mobx_1.autorun)(function (r) {
            var _a;
            // r.trace();
            if (isDataContainer && ((_a = currentWidget._scope) === null || _a === void 0 ? void 0 : _a.dataContext) && Object.values(currentWidget._scope.dataContext)) {
                forceUpate(function (_) {
                    return _ + 1;
                });
            }
        });
    }, []);
    React.useEffect(function () {
        return function () {
            dispose();
        };
    }, []);
    var totalContext = React.useMemo(function () {
        var _a;
        var _b;
        var res = isDataContainer && ((_b = currentWidget._scope) === null || _b === void 0 ? void 0 : _b.dataContext)
            ? tslib_1.__assign(tslib_1.__assign({}, _dataContext), (_a = {}, _a[id] = currentWidget._scope.dataContext, _a)) : _dataContext;
        return res;
    }, [_dataContext, _]);
    var watchedList = isInComposite
        ? [componentSchema]
        : [componentSchema, scopeContext, codeContext, injectContext, virtualFields];
    var staticResourceAttribute = ((_d = componentSchema.extra) === null || _d === void 0 ? void 0 : _d.staticResourceAttribute) || [];
    // 组件最终用于执行的事件函数
    var emit = React.useCallback((0, utils_1.generateEmit)(currentWidget, injectContext, isDataContainer
        ? [
            {
                key: "wa".concat(Date.now().toString().slice(-8)),
                trigger: 'onDataChange',
                isCapturePhase: false,
                data: {},
                dataBinds: {},
                instanceFunction: function (_a) {
                    var _b, _c, _d, _e, _f, _g;
                    var event = _a.event;
                    if (currentWidget._scope) {
                        if (currentWidget._scope.dataContext) {
                            if (!(0, lodash_es_1.isEqual)(currentWidget._scope.dataContext.data, (_b = event === null || event === void 0 ? void 0 : event.detail) === null || _b === void 0 ? void 0 : _b.data)) {
                                currentWidget._scope.dataContext.data = (_c = event === null || event === void 0 ? void 0 : event.detail) === null || _c === void 0 ? void 0 : _c.data;
                            }
                            if (!(0, lodash_es_1.isEqual)(currentWidget._scope.dataContext.state, (_d = event === null || event === void 0 ? void 0 : event.detail) === null || _d === void 0 ? void 0 : _d.state)) {
                                currentWidget._scope.dataContext.state = (_e = event === null || event === void 0 ? void 0 : event.detail) === null || _e === void 0 ? void 0 : _e.state;
                            }
                        }
                        else {
                            currentWidget._scope.dataContext = { data: (_f = event === null || event === void 0 ? void 0 : event.detail) === null || _f === void 0 ? void 0 : _f.data, state: (_g = event === null || event === void 0 ? void 0 : event.detail) === null || _g === void 0 ? void 0 : _g.state };
                        }
                    }
                    return event.detial;
                },
            },
        ]
        : [], {}), [currentWidget]);
    React.useLayoutEffect(function () {
        return function () {
            instanceRef.current = undefined;
        };
    }, []);
    React.useLayoutEffect(function () {
        if (currentWidget) {
            currentWidget._getInstanceRef = function () { return instanceRef; };
        }
    }, [currentWidget, instanceRef]);
    if (!Array.isArray(staticResourceAttribute)) {
        staticResourceAttribute = [];
    }
    // 判断为容器组件，则增加一个onDataChange事件
    if (isDataContainer && !(events === null || events === void 0 ? void 0 : events.includes('onDataChange'))) {
        events.push('onDataChange');
    }
    // 多个组件的 slot 属性
    var slotMetaMap = React.useMemo(function () {
        return (0, RenderWrapper_1.generateSlotMetaMap)(componentSchema, {
            scopeContext: scopeContext,
            codeContext: codeContext,
            virtualFields: virtualFields,
            updateContext: updateContext,
            injectContext: injectContext,
        }, {
            renderSlot: renderSlot,
        });
    }, watchedList);
    var slotMap = React.useMemo(function () {
        return generateSlotMap(slotMetaMap, {
            forContext: forContext,
            dataContext: totalContext,
        });
    }, [slotMetaMap, totalContext, forContext]);
    return (React.createElement(error_1.ErrorBoundary, { FallbackComponent: function (_a) {
            var error = _a.error;
            console.error("\u7EC4\u4EF6".concat(id, "\u53D1\u751F\u4E86\u9519\u8BEF\uFF0C\uFF1A").concat(error));
            return React.createElement("noscript", null);
        } },
        React.createElement(exports.DataContext.Provider, { value: totalContext },
            React.createElement(Field, { ref: instanceRef, data: tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, data), slotMap), { _selectableBlockEvents: {
                        // 选区的预览的click事件
                        onCustomEvent: function (_a) {
                            var index = _a.order, blockKey = _a.blockKey;
                            if (index !== undefined) {
                                indexRef.current = index;
                                typeRef.current = blockKey;
                            }
                        },
                        events: ((_e = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.selectableBlock) === null || _e === void 0 ? void 0 : _e.events.map(function (item) { return item.name; })) || [],
                        emit: function (trigger, eventData, domEvent) {
                            var _a, _b, _c;
                            return emit(trigger, typeRef.current &&
                                indexRef.current !== undefined &&
                                ((_c = (_b = (_a = data === null || data === void 0 ? void 0 : data[typeRef.current]) === null || _a === void 0 ? void 0 : _a[indexRef.current]) === null || _b === void 0 ? void 0 : _b.selectableBlock) === null || _c === void 0 ? void 0 : _c.listenerInstances), eventData, forContext, domEvent, scopeContext, totalContext);
                        },
                    } }), id: id, emit: function (trigger, eventData, domEvent) {
                    return emit(trigger, componentSchema.listenerInstances, eventData, forContext, domEvent, scopeContext, totalContext);
                }, events: events, compositeParent: compositeParent, forIndexes: forIndexes, "$node": currentWidget, domRef: setGetDomApi(currentWidget, { codeContext: codeContext }), style: style, className: className, staticResourceAttribute: staticResourceAttribute }, (0, RenderWrapper_1.getComponentChildren)(componentSchema, {
                virtualFields: virtualFields,
                codeContext: codeContext,
                forContext: forContext,
                injectContext: injectContext,
                scopeContext: scopeContext,
                dataContext: totalContext,
                updateContext: updateContext,
            })))));
}
function SlotElementWrapper(_a) {
    var component = _a.component, forContext = _a.forContext, dataContext = _a.dataContext;
    return component({ forContext: forContext, dataContext: dataContext });
}
function generateSlotMap(slots, _a) {
    var forContext = _a.forContext, dataContext = _a.dataContext;
    var map = {};
    Object.keys(slots).forEach(function (slotProp) {
        var meta = slots[slotProp];
        if (meta.type === 'HOC') {
            (0, lodash_es_1.set)(map, slotProp, meta.node({ dataContext: dataContext }));
        }
        else {
            (0, lodash_es_1.set)(map, slotProp, React.createElement(SlotElementWrapper, { component: meta.node, forContext: forContext, dataContext: dataContext }));
        }
    });
    return map;
}
function SlotWrapper(props) {
    return props.children;
}
function Page(props) {
    return props.children;
}
function getComponentRenderList(props) {
    var _a, _b, _c, _d, _e;
    var key = props.key, virtualFields = props.virtualFields, renderSlot = props.renderSlot, _f = props.codeContext, codeContext = _f === void 0 ? {} : _f, scopeContext = props.scopeContext, _g = props.genericComp, genericComp = _g === void 0 ? {} : _g, _h = props.emitEvents, emitEvents = _h === void 0 ? [] : _h, _j = props.componentSchema, componentSchema = _j === void 0 ? {} : _j, _k = props.forContext, forContext = _k === void 0 ? {} : _k, _l = props.injectContext, injectContext = _l === void 0 ? {} : _l, _m = props.rootNode, rootNode = _m === void 0 ? false : _m, dataContext = props.dataContext, updateContext = props.updateContext;
    var compId = componentSchema.id;
    var isInComposite = !!codeContext.$WEAPPS_COMP;
    // 判断 widgets 是从 page 来的，还是组件来的
    var widgetsData = !isInComposite ? codeContext.$page.widgets[compId] : codeContext.$WEAPPS_COMP.widgets[compId];
    var classNameList = (((_a = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.attributes) === null || _a === void 0 ? void 0 : _a.class) || '').split(/\s/).filter(function (item) { return !!item; });
    var dataBinds = ((_b = codeContext._dataBinds) === null || _b === void 0 ? void 0 : _b[compId]) || {};
    var FieldKey = genericComp['propName']
        ? codeContext.node[genericComp['propName']]
        : "".concat(componentSchema.module, ":").concat(componentSchema.component);
    var Field = componentSchema.type === 'PAGE' ? Page : virtualFields[FieldKey];
    var context = {
        scopeContext: scopeContext,
        forContext: forContext,
        codeContext: codeContext,
        dataContext: dataContext,
        virtualFields: virtualFields,
    };
    if ((0, utils_1.isSlot)(componentSchema)) {
        var SlotRender = !compId ? SlotWrapper : injectContext.SlotRender || SlotWrapper;
        var slotId = "".concat((_d = (_c = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.extra) === null || _c === void 0 ? void 0 : _c.__parent) === null || _d === void 0 ? void 0 : _d.id, ".").concat(compId);
        return (React.createElement(SlotRender, { component: slotId, componentSchema: componentSchema }, (0, RenderWrapper_1.getComponentChildren)(componentSchema, tslib_1.__assign(tslib_1.__assign({}, context), { injectContext: injectContext, updateContext: updateContext }))));
    }
    // For循环渲染
    var forList = getForList(compId, dataBinds, forContext, dataContext);
    if (forList) {
        return forList
            .map(function (item, index) {
            var _a;
            var _b;
            var forItemsIndexes = (forContext.forIndexes || []).concat(index);
            var forItems = tslib_1.__assign(tslib_1.__assign({}, forContext), (_a = {}, _a[compId] = item, _a.forIndexes = forItemsIndexes, _a));
            var _c = getBindData({
                widgetData: widgetsData,
                forItems: forItems,
                scopeContext: scopeContext,
                codeContext: codeContext,
                commonStyle: (_b = componentSchema.extra) === null || _b === void 0 ? void 0 : _b.commonStyle,
                classNameList: classNameList,
            }), forItemData = _c.fieldData, forItemStyle = _c.finalStyle, forItemClassNameList = _c.finalClassNameList;
            if (!(injectContext.checkVisible || utils_1.checkVisible)(forItemData)) {
                return null;
            }
            return (React.createElement(exports.ForContext.Provider, { key: forItemData._key, value: forItems },
                React.createElement(FieldWrapper, tslib_1.__assign({ Field: Field, componentSchema: componentSchema, context: tslib_1.__assign(tslib_1.__assign({}, context), { widgetsData: widgetsData, forContext: forItems, forIndexes: forItemsIndexes }), id: compId, updateContext: updateContext, data: tslib_1.__assign({}, forItemData) }, getSafeComponentProps({
                    style: forItemStyle,
                    classNameList: forItemClassNameList,
                }), { events: emitEvents, compositeParent: codeContext, renderSlot: renderSlot }))));
        })
            .filter(function (item) { return !!item; });
    }
    // 修正 forIndexes
    var forIndexes = getForIndexes(forContext, widgetsData);
    // 单节点渲染
    var _o = getBindData({
        widgetData: widgetsData,
        forItems: forContext,
        scopeContext: scopeContext,
        codeContext: codeContext,
        commonStyle: (_e = componentSchema.extra) === null || _e === void 0 ? void 0 : _e.commonStyle,
        classNameList: classNameList,
    }), fieldData = _o.fieldData, finalClassNameList = _o.finalClassNameList, finalStyle = _o.finalStyle;
    // false 或空字符串时
    if (!(injectContext.checkVisible || utils_1.checkVisible)(fieldData)) {
        return [];
    }
    return [
        React.createElement(FieldWrapper, tslib_1.__assign({ key: key, Field: Field, componentSchema: componentSchema, context: tslib_1.__assign(tslib_1.__assign({}, context), { widgetsData: widgetsData, forIndexes: forIndexes }), id: compId, updateContext: updateContext, data: tslib_1.__assign({}, fieldData) }, getSafeComponentProps({
            style: finalStyle,
            classNameList: finalClassNameList,
        }), { events: emitEvents, compositeParent: codeContext, renderSlot: renderSlot })),
    ];
}
exports.getComponentRenderList = getComponentRenderList;
exports.CompRenderer = (0, mobx_react_lite_1.observer)(function (props) {
    return getComponentRenderList(tslib_1.__assign(tslib_1.__assign({}, props), { scopeContext: React.createContext(exports.ScopeContext), forContext: React.useContext(exports.ForContext), injectContext: React.useContext(router_1.InjectContext) }));
});
function getFinalStyle(commonStyle, bindStyle, widgetStyle) {
    if (commonStyle === void 0) { commonStyle = {}; }
    if (bindStyle === void 0) { bindStyle = {}; }
    if (widgetStyle === void 0) { widgetStyle = {}; }
    var remBindStyle = typeof bindStyle === 'object' ? (0, cals_1.processCSSProperties2Rem)(bindStyle, { looseError: true }) : {};
    return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, ((0, cals_1.processCSSProperties2Rem)(commonStyle, { looseError: true }) || {})), ((0, cals_1.processCSSProperties2Rem)(widgetStyle, { looseError: true }) || {})), remBindStyle);
}
function getFinalClassNameList(classNameList, bindClassList, widgetClassList) {
    if (classNameList === void 0) { classNameList = []; }
    if (bindClassList === void 0) { bindClassList = []; }
    if (widgetClassList === void 0) { widgetClassList = []; }
    return [].concat(classNameList, bindClassList, widgetClassList);
}
// HACK: 从后向前保证循环的深度与 forIndexes 一致
// 后续需要将 For 循环迁移到外层
function getForIndexes(parentForItems, widgetsData) {
    return Array.isArray(widgetsData) && widgetsData.length > 0
        ? (parentForItems.forIndexes || []).slice(0 - getDeepArrLen(widgetsData))
        : undefined;
}
exports.getForIndexes = getForIndexes;
function getDeepArrLen(arr, len) {
    if (len === void 0) { len = 0; }
    if (Array.isArray(arr)) {
        return getDeepArrLen(arr[0], len + 1);
    }
    else {
        return len;
    }
}
function setGetDomApi(currentWidget, _a) {
    var codeContext = _a.codeContext;
    if (!currentWidget)
        return React.createRef();
    var isComposite = !currentWidget.widgetType.startsWith('gsd-h5-react');
    var isInComposite = !!(codeContext === null || codeContext === void 0 ? void 0 : codeContext.$WEAPPS_COMP);
    // 如果当前是复合组件，不做 getDom 的挂载
    if (!isComposite) {
        if (!currentWidget.domRef) {
            currentWidget.domRef = React.createRef();
        }
        if (!currentWidget.getDom) {
            currentWidget.getDom = function (options) { return (0, utils_1.getDom)(currentWidget.domRef.current, options); };
        }
        if (isInComposite && // 当前在复合组件内
            !currentWidget.parent && // 当前节点为复合组件的根节点
            codeContext.node && // 复合组件的 node 已经创建
            !codeContext.node.getDom // 复合组件的 node 未挂载 getDom 方法
        ) {
            codeContext.node.domRef = currentWidget.domRef;
            codeContext.node.getDom = currentWidget.getDom;
        }
    }
    return currentWidget.domRef;
}
//# sourceMappingURL=NodeRenderer.js.map