import * as React from 'react';
import { observer } from 'mobx-react-lite';
import {
  checkVisible,
  checkDisplay,
  getDom,
  generateEmit,
  isSlot,
  CALC_RPX_ROOT_VAL_NAME,
  generateWidgetAPIContext,
  checkObserverInstanceRef,
} from '../utils';
import { get, set, isEqual } from 'lodash-es';
import { generateSlotMetaMap, getComponentChildren, IContext } from './RenderWrapper';
import { InjectContext } from '../router';
import { ErrorBoundary } from '../utils/error';
import { processCSSPropertiesUnit } from '@cloudbase/cals';
import { autorun, observable } from 'mobx';
import { REPEATER } from '../utils/constants';
import { IFieldProps } from '../utils/hooks';

export const ForContext = React.createContext({});
export const ScopeContext = React.createContext({});
export const DataContext = React.createContext({});

interface IComponentRendererProps {
  componentSchema?: any;
  rootNode?: boolean;
  virtualFields: {
    [sourceKey: string]: React.FunctionComponent<any>;
  };
  slots?: {
    [slotName: string]: {
      type: 'HOC' | 'ELEMENT';
      node: React.FunctionComponent | React.ReactElement;
    };
  };
  renderSlot?: boolean;
  genericComp?: {
    propName: any;
  };
  scopeContext?: IContext['scopeContext'];
  codeContext?: IContext['codeContext'];
  emitEvents: string[];
  children: any;
  dataContext?: IContext['dataContext'];
  updateContext?: IContext['updateContext'];
}

const getSafeComponentProps = ({ style, classNameList }) => {
  const componentProps: {
    className?: string;
    style?: React.CSSProperties;
  } = {};

  if (classNameList.length) {
    componentProps.className = classNameList.join(' ');
  }

  if (style && Object.keys(style).length) {
    componentProps.style = style;
  }

  return componentProps;
};

// TODO: 需要不断移除 dataBinds(style/classList)
function getBindData({
  widgetData,
  forItems,
  scopeContext,
  codeContext,
  commonStyle = {},
  classNameList = [],
  injectContext = {},
}: {
  widgetData: any | any[];
  forItems: {
    [key: string]: any;
    forIndexes?: any[];
  };
  scopeContext: {
    [id: string]: any;
  };
  codeContext: IContext['codeContext'];
  commonStyle?: React.CSSProperties;
  classNameList?: string[];
  injectContext?: { processCssUnit?: 'px' | 'rpx' | 'rem'; checkDisplay?: () => boolean };
}) {
  // bindData
  if (Array.isArray(widgetData)) {
    widgetData =
      forItems.forIndexes === void 0 || widgetData.length === 0
        ? {}
        : get(widgetData, getForIndexes(forItems, widgetData));
  }
  widgetData = widgetData || {};
  const fieldData = { ...widgetData };

  const isRootNode = widgetData && !widgetData.parent;
  const isInComposite = !!codeContext.$WEAPPS_COMP;

  // 再次计算 scope value
  for (let key in fieldData) {
    if (Object.prototype.hasOwnProperty.call(fieldData, key)) {
      const 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
  let bindStyle = fieldData.style || {};
  /**
   * 若指令 hidden
   * 则相当于强制绑定了 display: 'none',
   */
  if (!(injectContext.checkDisplay || checkDisplay)(fieldData)) {
    bindStyle = {
      ...bindStyle,
      display: 'none',
    };
  }
  // 复合组件第一层需要将最外层样式 style 挂到节点上
  let cssStyle = commonStyle || {};
  let propStyle = isInComposite && isRootNode ? codeContext.$WEAPPS_COMP.props?.style || {} : {};
  const finalStyle = getFinalStyle(injectContext.processCssUnit, cssStyle, bindStyle, propStyle);

  // bindClassList
  const bindClassList = fieldData.classList || [];
  const finalClassNameList = getFinalClassNameList(classNameList, bindClassList);

  // 当前在复合组件中，且当前节点为根节点
  if (isInComposite && isRootNode) {
    if (widgetData.ownerWidget) {
      Object.keys(widgetData.ownerWidget).forEach((propName) => {
        if (propName === 'role' || ['aria-', 'data-'].some((prefix) => propName.startsWith(prefix))) {
          widgetData[propName] = widgetData.ownerWidget[propName];
        }
      });
    }
  }

  // 防止渲染时 data 的 style 与实际的 style 冲突
  delete fieldData.style;

  return {
    fieldData,
    finalStyle,
    finalClassNameList: Array.from(new Set(finalClassNameList)),
  };
}

const _FOR_ERROR_CACHE_MAP = {};

function getForList(compId, dataBinds, parentForItems, dataContext, $w, $scope) {
  /**
   * For循环渲染
   * @important
   * @default undfined // 代表没有进行for循环绑定
   */
  let forList = [];
  try {
    // 绑定了 for 变量，计算值最差应该是空数组
    // 没有绑定，那就是 undefined
    clearTimeout(_FOR_ERROR_CACHE_MAP[compId]);
    let list = dataBinds?._waFor
      ? dataBinds._waFor(parentForItems, undefined, dataContext, $w, $scope) || []
      : undefined;
    // 绑定了for 并且计算了值，但是不是数组类型，应该进行兜底
    if (list && !Array.isArray(list)) {
      list = [];
    }
    forList = list;
  } catch (e) {
    if ((window as any)?.__WEDA_LOG_LEVEL__ === 'debug') {
      // 计算值出错则使用空数组兜底
      _FOR_ERROR_CACHE_MAP[compId] = setTimeout(() => {
        console.debug(`${compId}循环绑定错误`, e);
      }, 1000);
    }
    forList = [];
  }

  if (forList && !Array.isArray(forList)) {
    _FOR_ERROR_CACHE_MAP[compId] = setTimeout(() => {
      console.warn(`${compId}循环绑定非数组值：`, forList);
    }, 1000);
    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;
//     };
//   })()
// );

interface IFieldWrapperPorps {
  Field: React.FunctionComponent<IFieldProps>;
  componentSchema: any;
  context: {
    virtualFields: IContext['virtualFields'];
    forContext: IContext['forContext'];
    forIndexes: number[];
    widgetsData: any;
    codeContext: IContext['codeContext'];
    // dataContext?: any;
  };
  id: string;
  data: {
    [key: string]: any;
  };
  updateContext?: IContext['updateContext'];
  style?: React.CSSProperties;
  className?: string;
  events: string[];
  compositeParent: any;
  renderSlot?: boolean;
  children?: any;
}

// FieldWrapper 依赖 currentWidgets scope 因此需要添加observer
const FieldWrapper = observer(_FieldWrapper);

function useObserverableRef(sourceKey = '') {
  const pureRef = React.useRef();
  const ref = React.useRef<any>();
  const observerRef = React.useMemo(() => {
    return checkObserverInstanceRef(sourceKey) ? observable(ref) : pureRef;
  }, []);

  return observerRef;
}

function useWidgetInstanceRef(widget) {
  const ref = useObserverableRef(widget?.widgetType);
  const _instanceRef = React.useRef();
  return React.useMemo(() => {
    if (widget) {
      if (widget._instanceRef !== _instanceRef.current) {
        _instanceRef.current = widget._instanceRef;
        widget._instanceRef.current = null;
      }
      return widget._instanceRef;
    }
    return ref;
  }, [widget?._instanceRef, ref]);
}

const emptyObject: Readonly<Record<string, unknown>> = {};
function _FieldWrapper({
  Field,
  componentSchema,
  id,
  data,
  style = emptyObject,
  className = '',
  events,
  compositeParent,
  context,
  updateContext,
  renderSlot = false,
}: IFieldWrapperPorps) {
  const {
    forContext,
    forIndexes,
    widgetsData,
    codeContext,
    //  dataContext,
    virtualFields,
  } = context;
  // trace(true);

  const injectContext = React.useContext(InjectContext);
  const scopeContext = React.useContext(ScopeContext);
  const _dataContext = React.useContext(DataContext);
  const indexRef = React.useRef();
  const typeRef = React.useRef();

  const [_, forceUpate] = React.useState(0);

  const isInComposite = !!codeContext.$WEAPPS_COMP;
  const isDataContainer = componentSchema?.extra?.compConfig?.isDataContainer;
  const currentWidget = Array.isArray(widgetsData) ? get(widgetsData, forIndexes) : widgetsData;
  const instanceRef = useWidgetInstanceRef(currentWidget);

  // context 变化强刷一次children，同时把 currentWidget._scope?.dataContext  添加到 observer 中
  const dispose = React.useMemo(() => {
    return autorun((r) => {
      // r.trace();
      if (isDataContainer && currentWidget?._scope?.dataContext && Object.values(currentWidget?._scope.dataContext)) {
        forceUpate((_) => {
          return _ + 1;
        });
      }
    });
  }, []);

  React.useEffect(() => {
    return () => {
      dispose();
    };
  }, []);

  const totalContext = React.useMemo(() => {
    const res =
      isDataContainer && currentWidget?._scope?.dataContext
        ? {
            ..._dataContext,
            [id]: currentWidget._scope.dataContext,
          }
        : _dataContext;
    return res;
  }, [_dataContext, _]);

  const watchedList = isInComposite
    ? [componentSchema]
    : [componentSchema, scopeContext, codeContext, injectContext, virtualFields];

  let staticResourceAttribute: string[] = componentSchema.extra?.staticResourceAttribute || [];

  // 组件最终用于执行的事件函数
  const emit = React.useCallback(
    generateEmit(
      (!isInComposite ? codeContext.$page : codeContext.$WEAPPS_COMP)?.__internal__?.$w,
      currentWidget,
      injectContext,
      isDataContainer
        ? [
            {
              key: `wa${Date.now().toString().slice(-8)}`,
              trigger: 'onDataChange',
              isCapturePhase: false,
              data: {},
              dataBinds: {},
              instanceFunction: ({ event }) => {
                if (currentWidget?._scope) {
                  if (currentWidget._scope.dataContext) {
                    if (!isEqual(currentWidget._scope.dataContext.data, event?.detail?.data)) {
                      currentWidget._scope.dataContext.data = event?.detail?.data;
                    }
                    if (!isEqual(currentWidget._scope.dataContext.state, event?.detail?.state)) {
                      currentWidget._scope.dataContext.state = event?.detail?.state;
                    }
                  } else {
                    currentWidget._scope.dataContext = { data: event?.detail?.data, state: event?.detail?.state };
                  }
                }
                return event.detial;
              },
            },
          ]
        : [],
      {},
    ),
    [currentWidget],
  );

  // 组件最终传给组件props的，要保持引用防rerender
  const emitFn = React.useCallback(
    (trigger, eventData, originalEvent) =>
      emit(
        trigger,
        componentSchema.listenerInstances,
        eventData,
        forContext,
        originalEvent,
        scopeContext,
        totalContext,
        !isInComposite ? codeContext.$page?.id : '',
      ),
    [componentSchema.listenerInstances, forContext, totalContext],
  );
  React.useLayoutEffect(() => {
    return () => {
      instanceRef.current = null;
    };
  }, []);

  React.useLayoutEffect(() => {
    return () => {
      instanceRef.current = null;
    };
  }, [currentWidget]);

  if (!Array.isArray(staticResourceAttribute)) {
    staticResourceAttribute = [];
  }

  // 判断为容器组件，则增加一个onDataChange事件
  if (isDataContainer && !events?.includes('onDataChange')) {
    events.push('onDataChange');
  }

  // 多个组件的 slot 属性
  const slotMetaMap = React.useMemo(() => {
    return generateSlotMetaMap(
      componentSchema,
      {
        scopeContext,
        codeContext,
        virtualFields,
        updateContext,
        injectContext,
      },
      {
        renderSlot,
      },
    );
  }, watchedList);

  const slotMap = React.useMemo(() => {
    return generateSlotMap(slotMetaMap, {
      forContext,
      dataContext: totalContext,
    });
  }, [slotMetaMap, totalContext, forContext]);

  const _selectableBlockEvents = React.useMemo(() => {
    const r = {
      // 选区的预览的click事件
      onCustomEvent: ({ order: index, blockKey }) => {
        if (index !== undefined) {
          indexRef.current = index;
          typeRef.current = blockKey;
        }
      },
      events: componentSchema?.selectableBlock?.events.map((item) => item.name) || [],
      emit: (trigger, eventData, originalEvent) =>
        emit(
          trigger,
          typeRef.current &&
            indexRef.current !== undefined &&
            data?.[typeRef.current as any]?.[indexRef.current as any]?.selectableBlock?.listenerInstances,
          eventData,
          forContext,
          originalEvent,
          scopeContext,
          totalContext,
        ),
    };
    return r;
  }, [componentSchema, totalContext, scopeContext, forContext]);

  return (
    <ErrorBoundary
      FallbackComponent={({ error }) => {
        console.error(`组件${id}发生了错误，：${error}`);
        return null;
      }}
    >
      <DataContext.Provider value={totalContext}>
        <Field
          ref={instanceRef}
          data={{
            ...data,
            ...slotMap,
            _selectableBlockEvents,
          }}
          id={id}
          emit={emitFn}
          events={events}
          /**
           * @deprecated
           * 老的复合组件
           * 和 Slot 组件依赖
           * 实际上应废弃
           */
          compositeParent={compositeParent}
          forIndexes={forIndexes}
          $node={currentWidget}
          $widget={currentWidget?._userWidget}
          domRef={setGetDomApi(currentWidget, { codeContext })}
          style={style}
          className={className}
          staticResourceAttribute={staticResourceAttribute}
          isInComposite={isInComposite}
        >
          {getComponentChildren(componentSchema, {
            virtualFields,
            codeContext,
            forContext,
            injectContext,
            scopeContext,
            dataContext: totalContext,
            updateContext,
          })}
        </Field>
      </DataContext.Provider>
    </ErrorBoundary>
  );
}

function SlotElementWrapper({ component, forContext, dataContext, codeContext = undefined }) {
  return component({ forContext, dataContext, codeContext });
}

function generateSlotMap(slots, { forContext, dataContext, codeContext = undefined }) {
  let map = {};
  Object.keys(slots).forEach((slotProp) => {
    let meta = slots[slotProp];
    if (meta.type === 'HOC') {
      set(map, slotProp, meta.node({ forContext, dataContext }));
    } else {
      set(
        map,
        slotProp,
        <SlotElementWrapper
          component={meta.node}
          forContext={forContext}
          dataContext={dataContext}
          codeContext={codeContext}
        />,
      );
    }
  });
  return map;
}

function SlotWrapper(props: any) {
  return props.children;
}

function Page(props) {
  return props.children;
}

export function getComponentRenderList(
  props: Omit<IComponentRendererProps, 'children'> & {
    key?: any;
    forContext: IContext['forContext'];
    injectContext: IContext['injectContext'];
    dataContext?: IContext['dataContext'];
    updateContext?: IContext['updateContext'];
  },
) {
  const {
    key,
    virtualFields,
    renderSlot,
    codeContext = {},
    scopeContext = {},
    genericComp = { propName: '' },
    emitEvents = [],
    componentSchema = {},
    forContext = {},
    injectContext = {},
    rootNode = false,
    dataContext,
    updateContext,
  } = props;
  const compId = componentSchema.id;

  const isInComposite = !!codeContext.$WEAPPS_COMP;
  // 判断 widgets 是从 page 来的，还是组件来的
  const widgetsData = !isInComposite ? codeContext.$page.widgets[compId] : codeContext.$WEAPPS_COMP.widgets[compId];

  const classNameList = (componentSchema?.attributes?.class || '').split(/\s/).filter((item) => !!item);

  const dataBinds = codeContext._dataBinds?.[compId] || {};
  const FieldKey = genericComp.propName
    ? codeContext.node[genericComp.propName]
    : `${componentSchema.module}:${componentSchema.component}`;

  const Field = componentSchema.type === 'PAGE' ? Page : virtualFields[FieldKey];

  const context = {
    scopeContext,
    forContext,
    codeContext,
    dataContext,
    virtualFields,
  };

  if (isSlot(componentSchema)) {
    const SlotRender = !compId ? SlotWrapper : injectContext.SlotRender || SlotWrapper;

    const slotId = `${componentSchema?.extra?.__parent?.id}.${compId}`;
    return (
      <SlotRender component={slotId} componentSchema={componentSchema} isComposite={isInComposite}>
        {getComponentChildren(componentSchema, {
          ...context,
          injectContext,
          updateContext,
        })}
      </SlotRender>
    );
  }

  /**
   * 这里逻辑的增加是为了支持 Repeater 组件和 $w 作用域
   * 此逻辑作用于 2 层循环组件绑定了 1 层循环项的数组值
   * 1. 补全 forContext.forStack
   * 2. 为 getForList 的 dataBinds._waFor 方法提供正确的 widget 实例
   */
  let currentForParentWidget = Array.isArray(widgetsData) ? get(widgetsData, forContext.forIndexes || []) : widgetsData;

  /**
   * get forIndexes 后仍为数组则说明当前节点是绑定for循环的
   * 会再多一级，此刻仅为了验证
   */
  if (Array.isArray(currentForParentWidget)) {
    /**
     * 提前判断纯属是为了减少 mobx warn
     * 不然访问空数组的[0]总是打一个 warn 出来
     */
    if (currentForParentWidget.length) {
      currentForParentWidget = currentForParentWidget[0]?.parent;
    } else {
      currentForParentWidget = undefined;
    }
  }

  // For循环渲染
  let forList = getForList(
    compId,
    dataBinds,
    forContext,
    dataContext,
    generateWidgetAPIContext(
      (!isInComposite ? codeContext.$page : codeContext.$WEAPPS_COMP)?.__internal__?.$w,
      currentForParentWidget,
      forContext,
      scopeContext,
    ),
    scopeContext,
  );

  if (forList) {
    return forList
      .map((item, index) => {
        let { forIndexes = [], forStack = [] } = forContext;
        const forItemsIndexes = forIndexes.concat(index);

        const currentWidget = Array.isArray(widgetsData) ? get(widgetsData, forItemsIndexes) : widgetsData;
        let forContextListAlias;
        const listMeta = { currentItem: item, currentIndex: index };

        switch (currentWidget?.widgetType) {
          case `${REPEATER.MODULE_NAME}:${REPEATER.REPEATER_ITEM_NAME}`:
          case `${REPEATER.DEBUG_MODULE_NAME}:${REPEATER.REPEATER_ITEM_NAME}`: {
            const repeaterWidget = currentWidget.parent;
            forContextListAlias = {
              [`${repeaterWidget.forIndex}` || 'currentIndex']: listMeta.currentIndex,
              [`${repeaterWidget.forItem}` || 'currentItem']: listMeta.currentItem,
            };
          }
        }
        const forItems = {
          ...forContext,
          [compId]: item,
          forIndexes: forItemsIndexes,
          forStack: [
            ...forStack,
            {
              ...listMeta,
              alias: forContextListAlias,
            },
          ],
        };

        const {
          fieldData: forItemData,
          finalStyle: forItemStyle,
          finalClassNameList: forItemClassNameList,
        } = getBindData({
          widgetData: widgetsData,
          forItems,
          scopeContext,
          codeContext,
          commonStyle: componentSchema.extra?.commonStyle,
          classNameList,
          injectContext: {
            ...injectContext,
            processCssUnit: isInComposite ? 'rpx' : injectContext.processCssUnit,
          } as any,
        });
        const { VisiblePlaceHolder } = injectContext;
        if (!(injectContext.checkVisible || checkVisible)(forItemData)) {
          return VisiblePlaceHolder ? <VisiblePlaceHolder id={compId} /> : null;
        }

        const filedElement = (
          <ForContext.Provider key={forItemData._key} value={forItems}>
            <FieldWrapper
              Field={Field}
              componentSchema={componentSchema}
              context={{
                ...context,
                widgetsData,
                forContext: forItems,
                forIndexes: forItemsIndexes,
              }}
              id={compId}
              updateContext={updateContext}
              data={forItemData}
              {...getSafeComponentProps({
                style: forItemStyle,
                classNameList: forItemClassNameList,
              })}
              events={emitEvents}
              compositeParent={codeContext}
              renderSlot={renderSlot}
            />
          </ForContext.Provider>
        );

        return !(injectContext.checkDisplay || checkDisplay)(forItemData) && VisiblePlaceHolder ? (
          <VisiblePlaceHolder id={compId}>{filedElement}</VisiblePlaceHolder>
        ) : (
          filedElement
        );
      })
      .filter((item) => !!item);
  }

  // 修正 forIndexes
  const forIndexes = getForIndexes(forContext, widgetsData);

  // 单节点渲染
  const { fieldData, finalClassNameList, finalStyle } = getBindData({
    widgetData: widgetsData,
    forItems: forContext,
    scopeContext,
    codeContext,
    commonStyle: componentSchema.extra?.commonStyle,
    classNameList,
    injectContext: { ...injectContext, processCssUnit: isInComposite ? 'rpx' : injectContext.processCssUnit } as any,
  });

  // false 或空字符串时
  if (!(injectContext.checkVisible || checkVisible)(fieldData)) {
    const { VisiblePlaceHolder } = injectContext;
    return VisiblePlaceHolder ? [<VisiblePlaceHolder key={key} id={compId} />] : [];
  }

  return [
    <FieldWrapper
      key={key}
      Field={Field}
      componentSchema={componentSchema}
      context={{
        ...context,
        widgetsData,
        forIndexes,
      }}
      id={compId}
      updateContext={updateContext}
      data={fieldData}
      {...getSafeComponentProps({
        style: finalStyle,
        classNameList: finalClassNameList,
      })}
      events={emitEvents}
      compositeParent={codeContext}
      renderSlot={renderSlot}
    >
      {/* 为了触发子组件的刷新，必要 */}
      {/* props 被 autorun ovserver 需要引起 props 变化 */}
      {/* {getComponentChildren(componentSchema, {
        virtualFields,
        codeContext,
        forContext,
        injectContext,
        scopeContext,
        dataContext,
        updateContext,
      })} */}
    </FieldWrapper>,
  ];
}

export const CompRenderer = observer(function (props: IComponentRendererProps) {
  return getComponentRenderList({
    ...props,
    scopeContext: React.createContext(ScopeContext),
    forContext: React.useContext(ForContext),
    injectContext: React.useContext(InjectContext),
  });
} as React.FunctionComponent<IComponentRendererProps>);

function getFinalStyle(type: 'px' | 'rem' | 'rpx', commonStyle = {}, bindStyle = {}, propStyle = {}) {
  const processOptions = {
    looseError: true,
    rpxCalcRoot: `var(${CALC_RPX_ROOT_VAL_NAME})`,
  };
  const processCssUnit = type || 'rem';
  const remBindStyle =
    typeof bindStyle === 'object' ? processCSSPropertiesUnit(bindStyle, processCssUnit, processOptions) : {};

  return {
    ...(processCSSPropertiesUnit(commonStyle, processCssUnit, processOptions) || {}),
    ...remBindStyle,
    ...propStyle,
  };
}

function getFinalClassNameList(classNameList = [], bindClassList = [], widgetClassList = []) {
  return [].concat(classNameList, bindClassList, widgetClassList);
}

// HACK: 从后向前保证循环的深度与 forIndexes 一致
// 后续需要将 For 循环迁移到外层
export function getForIndexes(parentForItems, widgetsData) {
  return Array.isArray(widgetsData) && widgetsData.length > 0
    ? (parentForItems.forIndexes || []).slice(0 - getDeepArrLen(widgetsData))
    : undefined;
}

function getDeepArrLen(arr, len = 0) {
  if (Array.isArray(arr)) {
    return getDeepArrLen(arr.length > 0 ? arr[0] : null, len + 1);
  } else {
    return len;
  }
}

function setGetDomApi(currentWidget, { codeContext }) {
  if (!currentWidget) return React.createRef();
  const isComposite = !currentWidget.widgetType.startsWith('gsd-h5-react');
  const isInComposite = !!codeContext?.$WEAPPS_COMP;

  // 如果当前是复合组件，不做 getDom 的挂载
  if (!isComposite) {
    if (!currentWidget.domRef) {
      currentWidget.domRef = React.createRef();
    }
    if (!currentWidget.getDom) {
      currentWidget.getDom = (options) => 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;
}
