import { __assign } from "tslib";
import * as React from 'react';
import { observer } from 'mobx-react-lite';
import { emitEvent, translateStyleToRem, checkVisible, isSlot } from '../utils';
import { get, set } from 'lodash-es';
import { getDom } from '../utils/widgets';
import { getComponentChildren, generateSlotMetaMap } from './RenderWrapper';
import { InjectContext } from '../router';
export var ForContext = 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, _c;
    var widgetData = _a.widgetData, forItems = _a.forItems, scopeContext = _a.scopeContext, codeContext = _a.codeContext, _d = _a.commonStyle, commonStyle = _d === void 0 ? {} : _d, _e = _a.classNameList, classNameList = _e === void 0 ? [] : _e;
    // bindData
    if (Array.isArray(widgetData)) {
        widgetData =
            forItems.forIndexes === void 0 || widgetData.length === 0
                ? {}
                : get(widgetData, getForIndexes(forItems, widgetData));
    }
    widgetData = widgetData || {};
    var fieldData = __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 '" + key + "' error:", e);
                    fieldData[key] = '';
                }
            }
        }
    }
    // bindStyle
    var bindStyle = fieldData.style || {};
    // 复合组件第一层需要将最外层样式 style 挂到节点上
    var cssStyle = commonStyle || {};
    if (isInComposite && isRootNode) {
        cssStyle = __assign(__assign({}, cssStyle), (((_b = codeContext.$WEAPPS_COMP.props) === null || _b === void 0 ? void 0 : _b.style) || {}));
        bindStyle = __assign(__assign({}, bindStyle), (((_c = codeContext.$WEAPPS_COMP.props) === null || _c === void 0 ? void 0 : _c.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)),
    };
}
function getForList(compId, dataBinds, parentForItems, dataContext) {
    /**
     * For循环渲染
     * @important
     * @default undfined // 代表没有进行for循环绑定
     */
    var forList = undefined;
    try {
        // 绑定了 for 变量，计算值最差应该是空数组
        // 没有绑定，那就是 undefined
        forList = (dataBinds === null || dataBinds === void 0 ? void 0 : dataBinds._waFor)
            ? dataBinds._waFor(parentForItems, undefined, dataContext) || []
            : undefined;
    }
    catch (e) {
        // 计算值出错则使用空数组兜底
        console.warn('_waFor data', e);
        forList = [];
    }
    // 绑定了for 并且计算了值，但是不是数组类型，应该进行兜底
    if (forList) {
        if (!Array.isArray(forList)) {
            console.warn(compId + "\u5FAA\u73AF\u7ED1\u5B9A\u975E\u6570\u7EC4\u503C\uFF1A", forList);
            forList = [];
        }
    }
    return forList;
}
// const FieldWrapper = React.memo(
//   _FieldWrapper,
//   (function () {
//     let latestRender = Date.now();
//     let latestTick = latestRender;
//     return (prevProps, nextProps) => {
//       const equal = isEqual(prevProps, nextProps);
//       const now = Date.now();
//       const delta = now - latestTick;
//       latestTick = now;
//       if (!equal && (delta > 10 || now - latestRender > 10)) {
//         latestRender = now;
//         return false;
//       }
//       return true;
//     };
//   })()
// );
var FieldWrapper = _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, children = _a.children, updateContext = _a.updateContext;
    var scopeContext = context.scopeContext, forContext = context.forContext, forIndexes = context.forIndexes, widgetsData = context.widgetsData, codeContext = context.codeContext, dataContext = context.dataContext;
    var injectContext = React.useContext(InjectContext);
    var indexRef = React.useRef();
    var typeRef = React.useRef();
    // 组件最终用于执行的事件函数
    var emit = React.useCallback(function (trigger, listeners, eventData, forItems, domEvent, scopeContext) {
        var _a, _b;
        // 当组件是数据容器并且listeners未含有onDataChange事件时，增加一个onDataChange事件
        if ((_b = (_a = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.extra) === null || _a === void 0 ? void 0 : _a.compConfig) === null || _b === void 0 ? void 0 : _b.isDataContainer) {
            listeners = listeners.concat({
                key: "wa" + Date.now().toString().slice(-8),
                trigger: 'onDataChange',
                isCapturePhase: false,
                data: {},
                dataBinds: {},
                instanceFunction: function (_a) {
                    var _b;
                    var event = _a.event;
                    return updateContext(id, (_b = event === null || event === void 0 ? void 0 : event.detail) === null || _b === void 0 ? void 0 : _b.data);
                },
            });
        }
        if (injectContext.emit) {
            return injectContext.emit(trigger, listeners, eventData, forItems, domEvent, scopeContext);
        }
        else {
            var event_1 = {
                detail: eventData,
                name: trigger,
                target: widgetsData,
                currentTarget: widgetsData,
                domEvent: domEvent,
            };
            forItems = __assign(__assign({}, forItems), { forIndexes: getForIndexes(forItems, widgetsData) });
            emitEvent(trigger, listeners, {
                event: event_1,
                customEventData: event_1,
                forItems: forItems,
                domEvent: domEvent,
            }, scopeContext, dataContext);
        }
    }, [widgetsData]);
    var currentWidget = Array.isArray(widgetsData)
        ? get(widgetsData, forIndexes)
        : widgetsData;
    var staticResourceAttribute = ((_b = componentSchema.extra) === null || _b === void 0 ? void 0 : _b.staticResourceAttribute) || [];
    if (!Array.isArray(staticResourceAttribute)) {
        staticResourceAttribute = [];
    }
    // 判断为容器组件，则增加一个onDataChange事件
    if (((_d = (_c = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.extra) === null || _c === void 0 ? void 0 : _c.compConfig) === null || _d === void 0 ? void 0 : _d.isDataContainer) &&
        !(events === null || events === void 0 ? void 0 : events.includes('onDataChange'))) {
        events.push('onDataChange');
    }
    return (React.createElement(Field, { data: __assign(__assign({}, data), { _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);
                },
            } }), id: id, emit: function (trigger, eventData, domEvent) {
            return emit(trigger, componentSchema.listenerInstances, eventData, forContext, domEvent, scopeContext);
        }, events: events, compositeParent: compositeParent, forIndexes: forIndexes, "$node": currentWidget, domRef: setGetDomApi(currentWidget, { codeContext: codeContext }), style: style, className: className, staticResourceAttribute: staticResourceAttribute }, children));
}
function generateSlotMap(slots, forContext) {
    var map = {};
    Object.keys(slots).forEach(function (slotProp) {
        var meta = slots[slotProp];
        if (meta.type === 'HOC') {
            set(map, slotProp, meta.node);
        }
        else {
            var Element_1 = meta.node;
            if (forContext) {
                set(map, slotProp, React.createElement(ForContext.Provider, { value: forContext },
                    React.createElement(Element_1, null)));
            }
            else {
                set(map, slotProp, React.createElement(Element_1, null));
            }
        }
    });
    return map;
}
function SlotWrapper(props) {
    return React.createElement(React.Fragment, null, props.children);
}
export function getComponentRenderList(props) {
    var _a, _b, _c, _d;
    var key = props.key, virtualFields = props.virtualFields, renderSlot = props.renderSlot, _e = props.codeContext, codeContext = _e === void 0 ? {} : _e, _f = props.scopeContext, scopeContext = _f === void 0 ? {} : _f, _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 = (codeContext._dataBinds && codeContext._dataBinds[compId]) || {};
    var FieldKey = genericComp['propName']
        ? codeContext.node[genericComp['propName']]
        : componentSchema.module + ":" + componentSchema.component;
    var Field = virtualFields[FieldKey];
    var context = {
        scopeContext: scopeContext,
        forContext: forContext,
        codeContext: codeContext,
        dataContext: dataContext,
    };
    if (isSlot(componentSchema)) {
        var SlotRender = !compId
            ? SlotWrapper
            : injectContext.SlotRender || SlotWrapper;
        var slotId = ((_c = (_b = componentSchema === null || componentSchema === void 0 ? void 0 : componentSchema.extra) === null || _b === void 0 ? void 0 : _b.__parent) === null || _c === void 0 ? void 0 : _c.id) + "." + compId;
        return (React.createElement(SlotRender, { component: slotId, componentSchema: componentSchema }, getComponentChildren(componentSchema, __assign(__assign({}, context), { virtualFields: virtualFields, 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 = __assign(__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 || checkVisible)(forItemData)) {
                return null;
            }
            // 多个组件的 slot 属性
            var slotMap = generateSlotMap(generateSlotMetaMap(componentSchema, __assign(__assign({}, context), { forContext: forItems, virtualFields: virtualFields, updateContext: updateContext, injectContext: injectContext }), {
                renderSlot: renderSlot,
            }));
            return (React.createElement(ForContext.Provider, { key: index, value: forItems },
                React.createElement(FieldWrapper, __assign({ Field: Field, componentSchema: componentSchema, context: __assign(__assign({}, context), { widgetsData: widgetsData, forContext: forItems, forIndexes: forItemsIndexes }), id: compId, updateContext: updateContext, data: __assign(__assign({}, forItemData), slotMap) }, getSafeComponentProps({
                    style: forItemStyle,
                    classNameList: forItemClassNameList,
                }), { events: emitEvents, compositeParent: codeContext }), getComponentChildren(componentSchema, {
                    virtualFields: virtualFields,
                    codeContext: codeContext,
                    scopeContext: scopeContext,
                    forContext: forItems,
                    injectContext: injectContext,
                    dataContext: dataContext,
                    updateContext: updateContext,
                }))));
        })
            .filter(function (item) { return !!item; });
    }
    // 修正 forIndexes
    var forIndexes = getForIndexes(forContext, widgetsData);
    // 单节点渲染
    var _o = getBindData({
        widgetData: widgetsData,
        forItems: forContext,
        scopeContext: scopeContext,
        codeContext: codeContext,
        commonStyle: (_d = componentSchema.extra) === null || _d === void 0 ? void 0 : _d.commonStyle,
        classNameList: classNameList,
    }), fieldData = _o.fieldData, finalClassNameList = _o.finalClassNameList, finalStyle = _o.finalStyle;
    // false 或空字符串时
    if (!(injectContext.checkVisible || checkVisible)(fieldData)) {
        return [];
    }
    // 多个组件的 slot 属性
    var slotMap = generateSlotMap(generateSlotMetaMap(componentSchema, __assign(__assign({}, context), { virtualFields: virtualFields, updateContext: updateContext, injectContext: injectContext }), {
        renderSlot: renderSlot,
    }));
    return [
        React.createElement(FieldWrapper, __assign({ key: key, Field: Field, componentSchema: componentSchema, context: {
                forIndexes: forIndexes,
                forContext: forContext,
                scopeContext: scopeContext,
                widgetsData: widgetsData,
                codeContext: codeContext,
                dataContext: dataContext,
            }, id: compId, updateContext: updateContext, data: __assign(__assign({}, fieldData), slotMap) }, getSafeComponentProps({
            style: finalStyle,
            classNameList: finalClassNameList,
        }), { events: emitEvents, compositeParent: codeContext }), getComponentChildren(componentSchema, {
            virtualFields: virtualFields,
            codeContext: codeContext,
            scopeContext: scopeContext,
            forContext: forContext,
            injectContext: injectContext,
            dataContext: dataContext,
            updateContext: updateContext,
        })),
    ];
}
export var CompRenderer = observer(function (props) {
    return getComponentRenderList(__assign(__assign({}, props), { forContext: React.useContext(ForContext), injectContext: React.useContext(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' ? translateStyleToRem(bindStyle) : {};
    return __assign(__assign(__assign({}, (translateStyleToRem(commonStyle) || {})), (translateStyleToRem(widgetStyle) || {})), 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;
}
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 || {}).$WEAPPS_COMP;
    // 如果当前是复合组件，不做 getDom 的挂载
    if (!isComposite) {
        if (!currentWidget.domRef) {
            currentWidget.domRef = React.createRef();
        }
        if (!currentWidget.getDom) {
            currentWidget.getDom = function (options) {
                return 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