import { getExtComponent } from '@alife/cn-lowcode-utils';
import isPlainObject from 'lodash/isPlainObject';
import get from 'lodash/get';
import isNaN from 'lodash/isNaN';
import isNumber from 'lodash/isNumber';
import trim from 'lodash/trim';
import uniq from 'lodash/uniq';
import qs from 'query-string';
import { customAlphabet } from 'nanoid';
import cloneDeep from 'lodash/cloneDeep';
import {
  componentMap as filterItemComponentMap,
  transRulesToValidator,
} from '../manager/filter-item';
import dayjs from 'dayjs';
import isArray from 'lodash/isArray';
import { getButtonAction, getItem as getButtonItem } from '../manager/button';
import merge from 'lodash/merge';

import {
  symbolMap,
  tableCurrentRowLabel,
  __arrayTableCurrentRow__,
  __dataSource__,
  __extraParam__,
  __paging__,
  __selectedRowKeys__,
  __selectedRowRecords__,
  __tableColumns__,
  __tableCurrentRow__,
  __tableData__,
  __tableExtra__,
  __tab_activeKey__,
  formDialogStateLabel,
  openDialogModeLabel,
  __stateValueOfSplit__,
  __formValue__,
  __filterValue__,
  __list_currentItem__,
} from './expr-const';
import { handleRequestParams, makeRequest } from '../manager/request';
import { CnMessage, CnIcon, CnButton } from '@cainiaofe/cn-ui-m';
import {
  _dataSourceName,
  allowSelectFirstComponentList,
  dataOriginRequest,
  dataOriginStatic,
  formUrlencoded,
  needSaveDataFlowActionList,
  preMokelayDomain,
  recursionComponentList,
} from '@/common/util/const';
import { ButtonPosition } from '@/type/button-position';
import { DisplayPosition } from '@/type/display-position';
import { ValidatorPosition } from '@/type/validator-position';
import {
  _getContext,
  _getFormValues,
} from '@/common/util/biz-component-prop-name';

// 缓存表单配置项
const cacheFormConfig = {};

const { VisualEngine } = window;
const Engine = VisualEngine;

export const __urlParams__ = '__urlParams__';
export const __record__ = '__record__';
export const __ds__ = '__ds__';
export const __blank__ = '__blank__';

const messageTypeMap = {
  success: 'success',
  warning: 'warning',
  error: 'error',
  notice: 'notice',
  help: 'help',
  loading: 'loading',
};

// 获取业务组件列表
export function getBizComponentNameList() {
  let result = [];
  if (VisualEngine) {
    const componentsMap = VisualEngine?.designer?.getComponentsMap?.();
    if (componentsMap) {
      result = Object.keys(componentsMap);
    }
  }
  return result;
}

function getRunTimeBizComponent(name) {
  if (name) {
    let result;
    const componentsMap = VisualEngine?.designer?.getComponentsMap?.();
    if (componentsMap && componentsMap[name]) {
      result = {
        componentName: name,
        component: {
          realize: () => {
            return componentsMap[name];
          },
        },
      };
    } else if (window.ConeRenderEngine) {
      const components = getRealComponents();
      if (components?.length > 0) {
        const com = components.find((item) => item.name === name);
        if (com && com.module) {
          result = {
            componentName: name,
            component: {
              realize: () => {
                return com.module;
              },
            },
          };
        }
      }
    } else {
      const com = getExtComponent(name);
      if (com) {
        result = {
          componentName: com.name,
          component: {
            realize: () => {
              return com.module;
            },
          },
        };
      }
    }
    if (isPlainObject(result)) {
      result.isBizComponent = true;
    }
    return result;
  }
}

function getRealComponents() {
  const components = window?.ConeRenderEngine?.core?.components;
  if (isArrayNotEmpty(components)) {
    return components;
  } else {
    return window?.renderContext?.rawComponents || [];
  }
}

function getRealResponse(res = {}) {
  const { status, data } = res;
  let result = res;
  if (status === 200 && data) {
    result = data;
  }
  return result;
}

export function getBizComponent(name, position) {
  if (name) {
    const componentMeta = VisualEngine?.designer?.getComponentMeta(name);
    if (componentMeta) {
      const { prototype } = componentMeta;
      if (prototype) {
        const config = prototype.getConfig?.();
        const packageName = prototype.getPackageName?.();
        if (config) {
          const runtimeComponent = getRunTimeBizComponent(name);
          const {
            title,
            category,
            cnLowCodeConfig,
            componentName,
            configure = [],
          } = config;
          if (cnLowCodeConfig && componentName && runtimeComponent) {
            const { position: comPosition = [] } = cnLowCodeConfig;
            if (comPosition.includes(position)) {
              const tempList = [
                DisplayPosition.filter,
                DisplayPosition.form,
                DisplayPosition.formDialog,
                DisplayPosition.tableCell,
                ButtonPosition.tableCell,
                ButtonPosition.tableOperate,
                ButtonPosition.tableBatchArea,
                ButtonPosition.tableToolArea,
                ButtonPosition.formDialog,
                ButtonPosition.form,
                ValidatorPosition.formDialog,
                ValidatorPosition.form,
                DisplayPosition.tableRowDetail,
                DisplayPosition.cnArrayTable,
                ButtonPosition.dialog,
                DisplayPosition.dialogTitle,
                ButtonPosition.formItemEvent,
                ButtonPosition.formDialogItemEvent,
              ];
              if (tempList.includes(position)) {
                const result = {
                  // 业务方
                  bizInfo: [
                    {
                      label: '业务组件',
                      value: 'common',
                    },
                  ],
                  category,
                  ...cnLowCodeConfig,
                  title,
                  componentName,
                  packageName,
                  component: {
                    realize: () => {
                      return VisualEngine.designer?.getComponentsMap?.()[
                        componentName
                      ];
                    },
                  },
                };
                if (configure?.length > 0) {
                  result.configure = configure;
                }
                return result;
              }
            }
          }
        }
      }
    }
  }
}

export function condition(prop, type, primaryKey) {
  return prop?.parent?.parent?.getPropValue?.(primaryKey) === type;
}

export function handlePrototypeCondition(
  prototypeList = [],
  componentName,
  primaryKey,
) {
  if (prototypeList?.length > 0) {
    return prototypeList.map((item) => {
      let newItem = item;
      if (isPlainObject(item)) {
        newItem = { ...item };
        newItem.__optType = componentName;
      }
      if (!newItem?.condition) {
        newItem.condition = function (prop) {
          return condition(prop, componentName, primaryKey);
        };
      }
      return newItem;
    });
  }
  return prototypeList;
}

export const generateIndex = (dataSourceList, componentName, key = 'value') => {
  let index = 2;
  while (
    dataSourceList.find((item) => item[key] === `${componentName}${index}`)
  ) {
    index++;
  }
  return index;
};

export function getRunTimeItem(componentMap, componentName) {
  let result;
  if (componentName) {
    result = componentMap[componentName];
    if (!result) {
      result = getRunTimeBizComponent(componentName);
    }
  }
  return result;
}

export const findNodeConfigListByDataSourceName = (config) => {
  const { dsNameKey, dsName } = config || {};
  const nodesMap = VisualEngine?.designer?.currentDocument?.nodesMap;
  const result: any = {
    configList: [],
    node: null,
  };
  if (nodesMap?.values()) {
    for (const item of nodesMap?.values()) {
      if (item?.getPropValue?.(dsNameKey) === dsName) {
        const { componentName } = item;
        if (componentName === 'CnTable') {
          result.configList = [
            {
              label: tableCurrentRowLabel,
              text: tableCurrentRowLabel,
              value: `state.${dsName}.${__tableCurrentRow__}`,
            },
            {
              label: '选中数据主键列表(selectedRowKeys)',
              text: '选中数据主键列表(selectedRowKeys)',
              value: `state.${dsName}.${__selectedRowKeys__}`,
            },
            {
              label: '选中数据列表(selectedRowRecords)',
              text: '选中数据列表(selectedRowRecords)',
              value: `state.${dsName}.${__selectedRowRecords__}`,
            },
            {
              label: '表格请求返回的数据(tableData)',
              text: '表格请求返回的数据(tableData)',
              value: `state.${dsName}.${__tableData__}`,
            },
            {
              label: '表格的列头(columns)',
              text: '表格的列头(columns)',
              value: `state.${dsName}.${__tableColumns__}`,
            },
            {
              label: '表格请求返回的分页信息(paging)',
              text: '表格请求返回的分页信息(paging)',
              value: `state.${dsName}.${__paging__}`,
              children: [
                {
                  label: '当前页(currentPage)',
                  text: '当前页(currentPage)',
                  value: `state.${dsName}.${__paging__}.currentPage`,
                },
                {
                  label: '每页显示几条(pageSize)',
                  text: '每页显示几条(pageSize)',
                  value: `state.${dsName}.${__paging__}.pageSize`,
                },
                {
                  label: '数据总个数(totalCount)',
                  text: '数据总个数(totalCount)',
                  value: `state.${dsName}.${__paging__}.totalCount`,
                },
              ],
            },
            {
              label: '请求返回的额外信息(extra)',
              text: '请求返回的额外信息(extra)',
              value: `state.${dsName}.${__tableExtra__}`,
            },
          ];
        } else if (componentName === 'CnTab') {
          result.configList = [
            {
              label: 'Tab的选中项',
              text: 'Tab的选中项',
              value: `state.${dsName}.${__tab_activeKey__}`,
            },
          ];
        } else if (componentName === 'CnList') {
          result.configList = [
            {
              label: 'List 当前点击项',
              text: 'List 当前点击项',
              value: `state.${dsName}.${__list_currentItem__}`,
            },
          ]
        } else {
          const configList = item?.getPropValue?.('config');
          if (Array.isArray(configList) && configList.length > 0) {
            const tempList = handleOriginList(
              configList,
              'label',
              'name',
              `state.${dsName}`,
              { dsName },
            );
            if (isArrayNotEmpty(tempList)) {
              result.configList = [...result.configList, ...tempList];
            }
          }
          if (componentName === 'CnFormDialog') {
            result.configList.push({
              label: formDialogStateLabel,
              children: [
                {
                  label: openDialogModeLabel,
                  value: `state.valueOf.${dsName}${__stateValueOfSplit__}openDialogMode`,
                },
              ],
            });
          }
        }
        result.node = item;
        break;
      }
    }
  }
  return result;
};

export function handleComponentTitle(title) {
  if (typeof title === 'string') {
    return title;
  } else if (isPlainObject(title)) {
    const { mock, type, value } = title;
    if (type === 'JSExpression') {
      if (mock) {
        return mock;
      } else {
        return '动态标题弹窗';
      }
    }
    return '动态标题';
  }
  return title;
}

export function handleI18nLabel(label) {
  if (isPlainObject(label) && label.type === 'cn-i18n') {
    return label.dm || '';
  }
  return label;
}

export function getNodeTitle(node) {
  const { propsData, componentName } = node || {};
  const { tableName } = propsData || {};
  let { title } = propsData || {};
  title = handleComponentTitle(handleI18nLabel(title));
  let realTitle = title;
  if (componentName === 'CnTable') {
    return tableName || '表格';
  }
  if (title) {
    if (componentName === 'CnFormDialog') {
      realTitle = `表单弹窗_${title}`;
    } else if (componentName === 'CnDialog') {
      realTitle = `弹窗_${title}`;
    }
    return realTitle;
  }
}

export const getDataSourceList = (config) => {
  const { typeList, needChildren } = config || {};
  const dataSource = VisualEngine?.context?.getManager('dataPool');
  const items = dataSource?.getItems();
  const result = [];
  if (items?.length > 0) {
    items.forEach((item) => {
      const { id, name, type, config: dsConfig } = item;
      const label = dsConfig?.description || name;
      const ds = {
        text: label,
        label,
        value: name,
        dataSourceId: dsConfig?.id,
        id,
      };
      const temp = findNodeConfigListByDataSourceName({
        dsNameKey: '_dataSourceName',
        dsName: name,
      });
      const { configList, node } = temp || {};
      const title = getNodeTitle(node);
      ds.componentName = node?.componentName;
      if (title) {
        ds.label = title;
        ds.text = title;
      }
      if (needChildren) {
        if (configList?.length > 0) {
          ds.children = configList;
        }
      }
      if (Array.isArray(typeList) && typeList.length > 0) {
        if (typeList.includes(type)) {
          result.push(ds);
        }
      } else {
        result.push(ds);
      }
    });
  }
  return result;
};

export const getDataSourceListWithAllPath = (config) => {
  const { typeList, needChildren, prototypeConfig } = config || {};
  const dataSource = VisualEngine?.context?.getManager('dataPool');
  const items = dataSource?.getItems();
  const result = [];
  const { flowList, currentFlowIndex } = prototypeConfig || {};
  if (items?.length > 0) {
    items.forEach((item) => {
      const { name, type, config: dsConfig } = item;
      const label = dsConfig?.description || name;
      const ds = {
        text: label,
        label,
        value: `state.${name}`,
      };
      const temp = findNodeConfigListByDataSourceName({
        dsNameKey: '_dataSourceName',
        dsName: name,
      });
      const { configList, node } = temp || {};
      const title = getNodeTitle(node);
      if (title) {
        ds.label = title;
        ds.text = title;
      }
      if (needChildren) {
        if (configList?.length > 0) {
          ds.children = configList;
        }
      }
      if (Array.isArray(typeList) && typeList.length > 0) {
        if (typeList.includes(type)) {
          result.push(ds);
        }
      } else {
        result.push(ds);
      }
    });
  }

  if (
    typeof currentFlowIndex === 'number' &&
    Array.isArray(flowList) &&
    flowList.length > 0
  ) {
    const existFlowList = flowList.slice(0, currentFlowIndex);
    if (existFlowList?.length > 0) {
      const extra: any = {
        label: '动作编排的数据',
        children: [],
      };
      existFlowList.forEach((item, index) => {
        const { optType, active, options } = item || {};
        if (optType && active === true) {
          if (needSaveDataFlowActionList.includes(optType)) {
            let realIndex = index;
            if (index === 0) {
              realIndex = '';
            }
            const currentFlowValue = `state.valueOf.${optType}${realIndex}`;
            let realLabel = '发请求';
            let children = [
              {
                label: 'success',
                value: `${currentFlowValue}.success`,
              },
              {
                label: 'data',
                value: `${currentFlowValue}.data`,
              },
              {
                label: 'msg',
                value: `${currentFlowValue}.msg`,
              },
            ];
            if (optType === 'submit') {
              realLabel = '提交';
            } else if (optType === 'jsbridge') {
              realLabel = '跨端JsBridge';
              children = [
                {
                  label: 'success',
                  value: `${currentFlowValue}.success`,
                },
                {
                  label: 'data',
                  value: `${currentFlowValue}.data`,
                },
                {
                  label: 'error',
                  value: `${currentFlowValue}.error`,
                },
              ];
            }
            extra.children.push({
              label: `${realLabel}${realIndex}`,
              value: currentFlowValue,
              children,
            });
          }
        }
      });
      if (extra.children.length > 0) {
        result.unshift(extra);
      }
    }
  }
  return result;
};

function getFlowListDataSource(config) {
  const result = [];
  const { currentFlowIndex, flowList } = config || {};
  if (
    typeof currentFlowIndex === 'number' &&
    Array.isArray(flowList) &&
    flowList.length > 0
  ) {
    const existFlowList = flowList.slice(0, currentFlowIndex);
    if (existFlowList?.length > 0) {
      existFlowList.forEach((item, index) => {
        const { optType, active } = item || {};
        if (optType && active !== false) {
          let flowLabel;
          if (optType === 'submit') {
            flowLabel = '提交';
          } else if (optType === 'request') {
            flowLabel = '发请求';
          }
          if (['request', 'submit'].includes(optType)) {
            let realIndex = index;
            if (index === 0) {
              realIndex = '';
            }
            const currentFlowValue = `${__dataSource__}.valueOf.${optType}${realIndex}`;
            result.push({
              label: `${flowLabel}${realIndex}`,
              value: currentFlowValue,
              children: [
                {
                  label: 'success',
                  value: `${currentFlowValue}.success`,
                },
                {
                  label: 'data',
                  value: `${currentFlowValue}.data`,
                },
                {
                  label: 'msg',
                  value: `${currentFlowValue}.msg`,
                },
              ],
            });
          }
        }
      });
    }
  }
  return result;
}

export function getRealizeValue(v) {
  if (v && typeof v.realize === 'function') {
    return v.realize();
  }
  return v;
}

export function isTextExpr(str) {
  if (typeof str === 'string' && str.length > 0) {
    if (str === __blank__) {
      return {
        prefix: __blank__,
      };
    } else if (str.startsWith(`${__record__}`)) {
      return {
        prefix: __record__,
        value: str.replace(`${__record__}.`, ''),
      };
    } else if (str.startsWith(__urlParams__)) {
      return {
        prefix: __urlParams__,
        value: str.replace(`${__urlParams__}.`, ''),
      };
    } else if (str.startsWith(__ds__)) {
      if (str.endsWith(__ds__)) {
        const dataSourceName = str.slice(6, str.lastIndexOf(__ds__));
        return {
          prefix: __ds__,
          dataSourceName,
        };
      } else {
        const index = str.indexOf(`${__ds__}.`);
        if (index > 0) {
          const dataSourceName = str.slice(6, index);
          const value = str.slice(index + 7);
          if (value && dataSourceName) {
            return {
              prefix: __ds__,
              value,
              dataSourceName,
            };
          }
        }
      }
    }
  }
  return false;
}

export function isValueObjectExpr(obj) {
  return !!(isPlainObject(obj) && obj.group && obj.param);
}

export function executeFunction(func, ...rest) {
  if (typeof func === 'function') {
    let result;
    try {
      result = func(...rest);
    } catch (e) {}
    return result;
  }
}

export function calculateTextExprValue(originValue, config = {}) {
  const textExpr = isTextExpr(originValue);
  const {
    urlParamsDataSource,
    recordDataSource,
    state,
    extraParamList = [],
    tableCurrentRow,
    extraParam,
    getExtraParam,
  } = config;
  if (textExpr) {
    const { prefix, value: textExprValue, dataSourceName } = textExpr;
    let temp;
    if (prefix === __blank__) {
      temp = undefined;
    } else if (prefix === __record__) {
      temp = recordDataSource;
    } else if (prefix === __urlParams__) {
      temp = urlParamsDataSource;
    } else if (prefix === __ds__ && dataSourceName) {
      temp = state?.[dataSourceName];
    }
    if (textExprValue) {
      return get(temp, textExprValue);
    } else {
      return temp;
    }
  } else if (typeof originValue === 'function') {
    try {
      let extra = extraParamList;
      if (!Array.isArray(extra)) {
        extra = [];
      }
      return originValue(recordDataSource, state, ...extra);
    } catch (e) {
      return;
    }
  } else if (isValueObjectExpr(originValue)) {
    const { group, param, secondParam, thirdParam } = originValue;
    if (group && param) {
      let result;
      let realExtraParam = extraParam;
      if (typeof getExtraParam === 'function') {
        realExtraParam = executeFunction(getExtraParam);
      }
      const objExprArgMap = {
        [__record__]: recordDataSource,
        [__dataSource__]: state,
        [__tableCurrentRow__]: tableCurrentRow,
        [__extraParam__]: realExtraParam,
      };
      if (secondParam) {
        result = get(
          objExprArgMap,
          `${group}.${param}.${secondParam}${
            thirdParam ? `.${thirdParam}` : ''
          }`,
        );
      } else {
        result = get(objExprArgMap, `${group}.${param}`);
      }
      return result;
    }
  }
  return originValue;
}

function calculateUrl(config, extra) {
  const { url, urlParams = [] } = config || {};
  if (url) {
    let search = '';
    const { urlParamsDataSource, recordDataSource, state, extraParamList } =
      extra || {};
    if (urlParams && urlParams.length > 0) {
      const temp = handleRequestParams(urlParams, {
        urlParamsDataSource,
        recordDataSource,
        state,
        extraParamList,
      });
      search = qs.stringify(temp);
    }

    let realUrl = calculateTextExprValue(url, {
      urlParamsDataSource,
      recordDataSource,
      state,
      extraParamList,
    });
    if (typeof realUrl === 'string' && realUrl.length > 0) {
      if (realUrl.indexOf('?') !== -1) {
        realUrl += `&${search}`;
      } else {
        realUrl += `?${search}`;
      }
      return realUrl;
    }
  }
}

export function makeFormItemSchema(config) {
  const {
    formItemConfig,
    isDesign,
    urlParams,
    formValue,
    state,
    usedComponentList,
    formProps,
    _context,
    formInstance,
    getFormInstance,
    isInCnFilterPro,
  } = config || {};
  const { formStyle } = formProps || {};
  const { readOnly: formReadOnly, allowCopy } = formStyle || {};

  const {
    label,
    name,
    componentName,
    rules = [],
    options = {},
    disabled,
    hidden,
    hasClear,
    tip,
    readOnly,
    placeholder,
    extra,
    colSpan,
    readOnlyClick,
    size,
    labelAlign,
    __advancedCodeConfig__,
  } = formItemConfig || {};
  const { handleProps } = __advancedCodeConfig__ || {};
  const title = label;
  const { dataOrigin } = options;

  let componentProps = { ...options };
  if (formReadOnly === true && allowCopy === true) {
    componentProps.readOnlyProps = {
      allowCopy: true,
    };
  }
  if (isPlainObject(readOnlyClick)) {
    if (readOnlyClick?.optType) {
      const action = getButtonAction({
        ...readOnlyClick,
        position: ButtonPosition.arrayTableCell,
      });
      if (action && !isDesign) {
        if (!componentProps.readOnlyProps) {
          componentProps.readOnlyProps = {};
        }

        if (typeof action === 'function') {
          componentProps.readOnlyProps.onClick = action.bind(null, {
            buttonConfig: readOnlyClick,
            state: _context?.state,
            urlParamsDataSource: urlParams,
            _context,
            position: ButtonPosition.arrayTableCell,
          });
        }
      }
    }
  }

  if (hasClear !== undefined) {
    componentProps.hasClear = hasClear;
  }
  if (size) {
    componentProps.size = size;
  }
  if (placeholder) {
    componentProps.placeholder = placeholder;
  }
  const componentDefine = getRunTimeItem(filterItemComponentMap, componentName);
  if (componentDefine) {
    const { isBizComponent } = componentDefine;
    if (isBizComponent === true) {
      componentProps[_getContext] = () => {
        return _context;
      };
    }
    let component = componentDefine?.component;
    component = getRealizeValue(component);
    const formBeforeHandler = component?.formBeforeHandler;
    if (formBeforeHandler) {
      componentProps = formBeforeHandler(componentProps, {
        isDesign,
        urlParamsDataSource: urlParams,
        recordDataSource: formValue,
        state,
        isInForm: true,
        formInstance,
        _context,
        getFormInstance,
      });
    }
  }
  const formItemProps = {};
  if (typeof colSpan === 'number') {
    formItemProps.colSpan = colSpan;
  }
  if (name && componentName && componentName !== 'CnAgreement') {
    let realComponentProps;
    if (typeof handleProps === 'function') {
      const extraProps = executeFunction(
        handleProps,
        { ...componentProps },
        _context?.state,
      );
      if (isPlainObject(extraProps)) {
        realComponentProps = merge(extraProps, { ...componentProps });
      }
    }
    if (!realComponentProps) {
      realComponentProps = { ...componentProps };
    }
    const formItem: any = {
      title,
      'x-component': componentName,
      'x-component-props': realComponentProps,
      'x-decorator': 'CnFormItem',
      ...formItemProps,
    };
    formItem['x-data'] = {
      disabled,
      hidden,
      readOnly,
    };
    formItem['x-decorator-props'] = {};
    if (tip) {
      formItem['x-decorator-props'].tip = tip;
    }
    if (labelAlign) {
      formItem['x-decorator-props'].labelAlign = labelAlign;
    }
    if (extra) {
      if (typeof extra === 'string') {
        formItem['x-decorator-props'].extra = extra;
      } else if (isPlainObject(extra)) {
        const { redirectType, text } = extra;
        const url = calculateUrl(extra, {
          urlParamsDataSource: urlParams,
          recordDataSource: formValue,
          state,
        });
        const extraProps = {
          style: { color: '#005be5' },
        };
        if (redirectType === 'open') {
          extraProps.target = '_blank';
        }
        if (url) {
          extraProps.href = url;
        }
        formItem['x-decorator-props'].extra = <a {...extraProps}>{text}</a>;
      } else if (typeof extra === 'function') {
        formItem['x-decorator-props'].extra = executeFunction(
          extra,
          formValue,
          state,
        );
      }
    }
    // if (typeof isReadOnly === 'boolean') {
    //   formItem.readOnly = isReadOnly;
    // }
    // if (typeof isHidden === 'boolean') {
    //   formItem['x-hidden'] = isHidden;
    //   // formItem['x-display'] = isHidden ? 'none' : 'visible'
    // }
    // if (typeof isDisabled === 'boolean') {
    //   formItem['x-disabled'] = isDisabled;
    // }
    usedComponentList.push(componentName);
    if (rules.length > 0) {
      formItem['x-validator'] = transRulesToValidator(rules, {
        formValue,
        state,
        position: ValidatorPosition.form,
      });
    }
    if (componentDefine) {
      const formItemBeforeHandler = componentDefine?.formItemBeforeHandler;
      if (formItemBeforeHandler) {
        formItemBeforeHandler(formItem, {
          formItemConfig,
          formProps,
          isDesign,
          usedComponentList,
          urlParams,
          formValue,
          state,
          _context,
          formInstance,
        });
      }
    }
    const ds = formItem['x-component-props']?.dataSource;
    if (dataOrigin === 'static') {
      if (Array.isArray(ds) && ds.length > 0) {
        formItem.enum = ds;
      }
      if (formItem?.['x-component-props']?.dataSource) {
        if (componentName === 'CnAsyncSelect' || isInCnFilterPro) {
        } else {
          delete formItem['x-component-props'].dataSource;
        }
      }
    }
    return formItem;
  }
}

function compileLeft(str) {
  let left = trim(str);
  let attr;
  let urlParamsKey;
  let dataSourceName;
  if (left) {
    left = left.replaceAll('"', '');
    left = left.replaceAll("'", '');
    if (left) {
      if (left.startsWith(`${__urlParams__}.`)) {
        attr = __urlParams__;
        urlParamsKey = left.replace(`${__urlParams__}.`, '');
      } else if (left.startsWith(`${__ds__}`)) {
        const index = left.lastIndexOf(`${__ds__}`);
        if (index > 0) {
          attr = str.slice(0, index + 6);
          urlParamsKey = str.slice(index + 7);
          dataSourceName = str.slice(6, index);
        }
      } else {
        attr = left;
      }
    }
  }
  return {
    attr,
    urlParamsKey,
    dataSourceName,
  };
}

const symbolList = ['>=', '<=', '>', '<', '!==', '!=', '===', '==', '='];

export function compileTextExpr2(str, type = null) {
  if (!str) {
    str = '';
  }
  let attr;
  let value;
  let symbol;
  let realType;
  let urlParamsKey;
  let dataSourceName;
  try {
    if (typeof str === 'string' && str.length > 0) {
      symbol = symbolList.find((item) => str.includes(item));
      try {
        let left;
        let right;
        if (symbol) {
          const list = str.split(symbol);
          left = trim(list[0]);
          left = left.replaceAll('"', '');
          left = left.replaceAll("'", '');
          right = trim(list[1]);
        } else {
          left = str;
        }

        if (left) {
          const leftResult = compileLeft(left);
          if (leftResult.attr) {
            attr = leftResult.attr;
          }
          if (leftResult.urlParamsKey) {
            urlParamsKey = leftResult.urlParamsKey;
          }
          if (leftResult.dataSourceName) {
            dataSourceName = leftResult.dataSourceName;
          }
        }
        if (right) {
          const tempSymbol = ['"', '"', "'"];
          const tempSymbolFirst = tempSymbol.find((item) =>
            right.includes(item),
          );
          if (tempSymbolFirst) {
            right = right.slice(
              right.indexOf(tempSymbolFirst) + 1,
              right.lastIndexOf(tempSymbolFirst),
            );
            realType = 'string';
          } else if (right === 'true' || right === 'false') {
            realType = 'boolean';
          } else {
            const temp = Number(right);
            if (isNumber(temp) && !isNaN(temp)) {
              realType = 'number';
            }
          }
          if (right) {
            if (!type) {
              type = realType;
            }
            if (type === 'boolean') {
              value = right === 'true';
            } else if (type === 'number') {
              const temp = Number(right);
              if (isNumber(temp) && !isNaN(temp)) {
                value = temp;
              } else {
                value = undefined;
              }
            } else if (type === 'string') {
              value = right;
            } else {
              value = right;
            }
          }
        }
      } catch (e) {}
    }
  } catch (e) {}

  return {
    attr,
    value,
    symbol,
    type: realType,
    urlParamsKey,
    dataSourceName,
  };
}

function transTextExprToFunction(str) {
  const expr = compileTextExpr2(str);
  if (expr) {
    const { attr, value, symbol, urlParamsKey, dataSourceName } = expr;
    try {
      if (attr && symbol) {
        if (attr.startsWith(__ds__)) {
          if (urlParamsKey && dataSourceName) {
            switch (symbol) {
              case '>':
                return (record, params, state) => {
                  return get(state?.[dataSourceName], urlParamsKey) > value;
                };
              case '<':
                return (record, params, state) => {
                  return get(state?.[dataSourceName], urlParamsKey) < value;
                };
              case '>=':
                return (record, params, state) => {
                  return get(state?.[dataSourceName], urlParamsKey) >= value;
                };
              case '<=':
                return (record, params, state) => {
                  return get(state?.[dataSourceName], urlParamsKey) <= value;
                };
              case '===':
              case '==':
              case '=':
                if (value === undefined || value === null || value === '') {
                  return (record, params, state) => {
                    return !get(state?.[dataSourceName], urlParamsKey);
                  };
                } else {
                  return (record, params, state) => {
                    return get(state?.[dataSourceName], urlParamsKey) === value;
                  };
                }
              case '!==':
              case '!=':
                if (value === undefined || value === null || value === '') {
                  return (record, params, state) => {
                    return !!get(state?.[dataSourceName], urlParamsKey);
                  };
                } else {
                  return (record, params, state) => {
                    return get(state?.[dataSourceName], urlParamsKey) !== value;
                  };
                }
            }
          }
        } else if (attr === __urlParams__) {
          if (urlParamsKey) {
            switch (symbol) {
              case '>':
                return (record, params) => {
                  return params?.[urlParamsKey] > value;
                };
              case '<':
                return (record, params) => {
                  return params?.[urlParamsKey] < value;
                };
              case '>=':
                return (record, params) => {
                  return params?.[urlParamsKey] >= value;
                };
              case '<=':
                return (record, params) => {
                  return params?.[urlParamsKey] <= value;
                };
              case '===':
              case '==':
              case '=':
                if (value === undefined || value === null || value === '') {
                  return (record, params) => {
                    return !params?.[urlParamsKey];
                  };
                } else {
                  return (record, params) => {
                    return params?.[urlParamsKey] === value;
                  };
                }
              case '!==':
              case '!=':
                if (value === undefined || value === null || value === '') {
                  return (record, params) => {
                    return !!params?.[urlParamsKey];
                  };
                } else {
                  return (record, params) => {
                    return params?.[urlParamsKey] !== value;
                  };
                }
            }
          }
        } else if (attr.startsWith(`${__record__}.`)) {
          const realAttr = attr.slice(`${__record__}.`.length);
          if (realAttr) {
            switch (symbol) {
              case '>':
                return (record) => {
                  return record?.[realAttr] > value;
                };
              case '<':
                return (record) => {
                  return record?.[realAttr] < value;
                };
              case '>=':
                return (record) => {
                  return record?.[realAttr] >= value;
                };
              case '<=':
                return (record) => {
                  return record?.[realAttr] <= value;
                };
              case '===':
              case '==':
              case '=':
                if (value === undefined || value === null || value === '') {
                  return (record) => {
                    return !record?.[realAttr];
                  };
                } else {
                  return (record) => {
                    return record?.[realAttr] === value;
                  };
                }
              case '!==':
              case '!=':
                if (value === undefined || value === null || value === '') {
                  return (record) => {
                    return !!record?.[realAttr];
                  };
                } else {
                  return (record) => {
                    return record?.[realAttr] !== value;
                  };
                }
            }
          }
        }
      }
    } catch (e) {}
  }
}

// 执行对象表达式
export function executeObjectExpr(str, objExprArgMap, ...args) {
  if (typeof str === 'boolean') {
    return str;
  } else if (typeof str === 'function') {
    let result;
    try {
      const params = args.map((item) => {
        if (item === null || item === undefined) {
          return {};
        }
        return item;
      });
      result = str(...params);
    } catch (e) {
      console.error(e);
    }
    if (typeof result === 'boolean') {
      return result;
    }
  } else if (typeof str === 'string' && str.length > 0) {
    const func = transTextExprToFunction(str);
    const params = [...args];
    let first = {};
    let last = {};
    let state = {};
    if (params.length > 0) {
      first = args[0] || {};
      state = args[args.length - 1];
      if (state && state.urlParams) {
        last = state.urlParams;
      }
    }
    const result = executeFunction(func, first, last, state || {});
    if (typeof result === 'boolean') {
      return result;
    }
  } else if (isPlainObject(str)) {
    const { group, param, secondParam, symbol, type, value, thirdParam } = str;
    if (group && param && symbol) {
      let leftValue;
      if (group === __dataSource__) {
        if (secondParam) {
          leftValue = get(
            objExprArgMap,
            `${group}.${param}.${secondParam}${
              thirdParam ? `.${thirdParam}` : ''
            }`,
          );
        }
      } else {
        leftValue = get(objExprArgMap, `${group}.${param}`);
      }
      const func = symbolMap[symbol];
      if (typeof func === 'function') {
        const result = func(leftValue, value, str);
        if (typeof result === 'boolean') {
          return result;
        }
      }
    }
  }
}

export function isDesignMode(props) {
  let mode;
  if (isPlainObject(props)) {
    mode = props?.__designMode;
  } else if (typeof props === 'string') {
    mode = props;
  }
  return mode === 'design';
}

export function getItem(
  componentMap,
  position,
  componentName,
  propKey,
  extraQueryParams,
) {
  let result;
  if (componentName) {
    let item = componentMap[componentName];
    if (!item) {
      item = getBizComponent(componentName, position);
    }
    if (typeof item === 'function') {
      item = executeFunction(item, { position });
    }
    let flag = true;
    if (item && item.position && item.position.includes(position)) {
    } else {
      flag = false;
    }
    if (isPlainObject(extraQueryParams)) {
      for (const key in extraQueryParams) {
        if (key && Array.isArray(item?.[key])) {
          if (item[key].includes(extraQueryParams[key])) {
          } else {
            flag = false;
          }
        }
      }
    }
    if (flag) {
      if (!item.label) {
        item.label = item.title;
      }
      if (!item.value) {
        item.value = item.componentName;
      }
      if (propKey) {
        result = item[propKey];
      } else {
        result = item;
      }
    }
  }
  return result;
}

export function getItemPrototypeListByPosition(config) {
  const { position, primaryKey, componentMap } = config;
  const defaultList = Object.keys(componentMap);
  const bizComponentNameList = getBizComponentNameList();
  let prototypeList: any = [];
  const allComponentList = uniq([...defaultList, ...bizComponentNameList]);
  allComponentList.forEach((name) => {
    const item = getItem(componentMap, position, name) || {};
    const { getPrototypeList, configure = [] } = item;
    if (typeof getPrototypeList === 'function') {
      const temp = getPrototypeList(position);
      if (temp && temp.length > 0) {
        prototypeList = [
          ...prototypeList,
          ...handlePrototypeCondition(temp, name, primaryKey),
        ];
      }
    } else if (configure?.length > 0) {
      prototypeList = [
        ...prototypeList,
        ...handlePrototypeCondition(configure, name, primaryKey),
      ];
    }
  });
  return prototypeList;
}

export function getItemDefaultProps(componentMap, position, componentName) {
  const func = getItem(
    componentMap,
    position,
    componentName,
    'getDefaultProps',
  );
  if (typeof func === 'function') {
    return func();
  }
}

export function getItemListByPosition(config) {
  const { position, componentMap, extraQueryParams } = config;
  const result = [];
  const defaultList = Object.keys(componentMap);
  const bizComponentNameList = getBizComponentNameList();
  const allComponentList = uniq([...defaultList, ...bizComponentNameList]);
  allComponentList.forEach((name) => {
    const component = getItem(
      componentMap,
      position,
      name,
      null,
      extraQueryParams,
    );
    if (component) {
      const { bizInfo = [] } = component;
      if (bizInfo.length > 0) {
        bizInfo.forEach((item) => {
          const { label, value } = item;
          const existGroup = result.find((item2) => item2.value === value);
          if (existGroup) {
            existGroup?.children.push(component);
          } else {
            result.push({
              title: label,
              value,
              children: [component],
            });
          }
        });
        return;
      }
      result.push(component);
    }
  });
  return result;
}

export function isArrayNotEmpty(list) {
  return Array.isArray(list) && list.length > 0;
}

function uuid(len = 4) {
  return customAlphabet('abcdefghijklmnopqrstuvwxyz', len)();
}

export function getDsNameFromVariable(dsExpr) {
  let result = '';
  if (dsExpr && dsExpr.variable) {
    result = dsExpr.variable.slice(dsExpr.variable.lastIndexOf('.') + 1);
  }
  return result;
}

export function generateDataSource(config) {
  const { componentName } = config || {};
  if (componentName) {
  }
  let dataSourceList = [];
  dataSourceList = getDataSourceList();
  let index = '';
  const first = dataSourceList?.find(
    (item) => item.value === `${componentName}`,
  );
  if (first) {
    index = generateIndex(dataSourceList, componentName);
  }
  if (Engine) {
    const componentPrototype =
      Engine?.designer?.getComponentMeta?.(componentName)?.prototype;
    const dataSource = Engine?.context?.getManager('dataPool');
    const ds = dataSource?.addItem({
      description: `${
        componentPrototype?.options?.title || componentName
      }${index}的数据源`,
      dpType: 'VALUE',
      id: '',
      initialData: '',
      isGlobal: false,
      name: `${componentName}${index}`,
      protocal: 'VALUE',
    });
    if (ds?.name) {
      return ds;
    }
  }
}

export function handleSuccessMessage(res) {
  const { msg, extra } = res || {};
  const { type } = extra || {};
  let resultType = 'success';
  if (messageTypeMap[type]) {
    resultType = type;
  }
  CnMessage[resultType](msg || '请求成功');
}

// 处理设计态时的表单项缩进
export function handleDesignFormConfig(tconfig) {
  const { nodeId, newFormConfig } = tconfig || {};
  const oldNodeConfig = cacheFormConfig[nodeId];
  if (oldNodeConfig) {
    const { formConfigLength, formConfig } = oldNodeConfig;
    if (formConfigLength === newFormConfig?.length) {
      let isSame = true;
      for (const index in formConfig) {
        const newItem = newFormConfig?.[index];
        const oldItem = formConfig[index];
        if (newItem?.componentName !== oldItem?.componentName) {
          isSame = false;
          break;
        }
      }
      if (isSame === true) {
        const first = document.querySelector('.lc-sortable')?.children?.[0];
        const handled = first?.getAttribute?.('handled');
        if (handled === 'handled') {
          return;
        }
      }
    }
  }
  console.info('design: form handle indent');
  handleFormConfigIndent({
    config: newFormConfig,
    formInfo: getFormInfo(newFormConfig) || {},
    children: document.querySelector('.lc-sortable')?.children,
  });
  cacheFormConfig[nodeId] = {
    formConfigLength: newFormConfig?.length,
    formConfig: newFormConfig?.map((item) => {
      return {
        componentName: item.componentName,
        name: item.name,
      };
    }),
  };
}

// 计算表单字段的缩进
function handleFormConfigIndent(config) {
  const { config: fieldConfig, formInfo, children } = config || {};
  const { isFormStep, isFormTab, hasCard } = formInfo || {};
  if (isArrayNotEmpty(fieldConfig)) {
    fieldConfig.forEach((item, index) => {
      const { componentName, name } = item || {};
      if (name && componentName) {
        let backgroundColor;
        let borderTopLeftRadius;
        let padding;
        let marginLeft;
        const currentDom = children?.[index];
        if (isFormStep || isFormTab) {
          if (
            componentName === 'CnFormStepItem' ||
            componentName === 'CnFormTabItem'
          ) {
            backgroundColor = '#cbd9ff';
            borderTopLeftRadius = '5px';
            padding = '3px';
            marginLeft = '0px';
          } else {
            borderTopLeftRadius = '0px';
            padding = '0px';
            marginLeft = '12px';
            backgroundColor = '#f0f2ff';
          }
        } else if (hasCard) {
          if (componentName === 'CnCard') {
            backgroundColor = '#cbd9ff';
            borderTopLeftRadius = '5px';
            padding = '3px';
            marginLeft = '0px';
          } else {
            borderTopLeftRadius = '0px';
            padding = '0px';
            marginLeft = '12px';
            backgroundColor = '#f0f2ff';
          }
        }
        if (currentDom?.style) {
          if (index === 0) {
            currentDom.setAttribute('handled', 'handled');
          }
          currentDom.style.borderTopLeftRadius = borderTopLeftRadius;
          currentDom.style.padding = padding;
          currentDom.style.marginLeft = marginLeft;
          currentDom.style.backgroundColor = backgroundColor;
        }
      }
    });
  }
}

function getFormInfo(originalConfig) {
  let firstFormStep;
  let isFormStep = false;
  let isFormTab = false;
  let hasCard = false;
  let firstFormTabIndex = 0;
  if (isArrayNotEmpty(originalConfig)) {
    for (const index in originalConfig) {
      const item = originalConfig[index];
      if (item?.componentName === 'CnFormStepItem') {
        firstFormStep = item;
        isFormStep = true;
        break;
      } else if (item?.componentName === 'CnFormTabItem') {
        isFormTab = true;
        firstFormTabIndex = +index;
        break;
      } else if (item?.componentName === 'CnCard') {
        hasCard = true;
      }
    }
  }
  return {
    firstFormStep,
    isFormStep,
    isFormTab,
    firstFormTabIndex,
    hasCard,
  };
}

function visibleRun(extraProps, visible, type, run) {
  // const { requestConfig, state, recordDataSource } = extraProps || {}
  // const execute = calculateRequestExecute(requestConfig, {
  //   [__formValue__]: recordDataSource,
  //   [__filterValue__]: recordDataSource,
  //   [__dataSource__]: state,
  // }, recordDataSource || {}, state)
  if (visible) {
    run?.();
  }
}

function handleFormUrlencodedContentType(requestConfig) {
  if (
    requestConfig?.serviceType === 'http' &&
    requestConfig?.contentType === formUrlencoded
  ) {
    requestConfig.headers = {
      'content-type': formUrlencoded,
    };
  }
}

// 处理设计态的mokelay请求url
const handleDesignMokelayUrl = (url) => {
  const domain = window.getCnLowcodeStoreItem?.('__next_cone_domain__');
  if (domain && domain?.value) {
    return `${location.protocol}//${domain.value}${url}`;
  }
  return preMokelayDomain + url;
};

function handleSelectRequestConfig(config) {
  const {
    componentProps,
    isDesign,
    urlParamsDataSource,
    recordDataSource,
    state,
    ignoreHandleParam,
  } = config || {};
  if (isPlainObject(componentProps)) {
    const { dataOrigin, extraProps } = componentProps;
    if (dataOrigin === 'request') {
      // if (componentProps?.requestConfig?.url) {
      delete componentProps.dataSource;
      // }
      if (componentProps?.requestConfig?.serviceType === 'mokelay') {
        componentProps.requestConfig.method = 'post';
        if (isDesign && componentProps?.requestConfig?.url) {
          componentProps.requestConfig.url = handleDesignMokelayUrl(
            componentProps.requestConfig?.url,
          );
        }
      } else if (componentProps?.requestConfig) {
        componentProps.requestConfig.withCredentials = true;
      }
      if (
        ignoreHandleParam !== true &&
        Array.isArray(componentProps?.requestConfig?.params) &&
        componentProps?.requestConfig?.params.length > 0
      ) {
        const realParams = handleRequestParams(
          componentProps?.requestConfig?.params,
          {
            urlParamsDataSource,
            recordDataSource,
            state,
          },
        );
        if (realParams) {
          if (componentProps?.requestConfig?.method === 'post') {
            componentProps.requestConfig.data = realParams;
            delete componentProps.requestConfig.params;
          } else {
            componentProps.requestConfig.params = realParams;
          }
        }
      }
      if (
        componentProps?.requestConfig?.serviceType !== 'mock' &&
        typeof componentProps?.requestConfig?.resultProcessFunc === 'function'
      ) {
        componentProps.requestConfig.formatResult = (res) => {
          let newRes = getRealResponse(res);
          try {
            newRes = componentProps?.requestConfig?.resultProcessFunc(newRes);
          } catch (e) {
            console.error('请求结果回调执行失败', e);
          }

          if (Array.isArray(newRes?.data)) {
            newRes = newRes.data;
          } else if (Array.isArray(newRes?.data?.dataSource)) {
            newRes = newRes?.data?.dataSource;
          }
          return newRes;
        };
      } else if (
        componentProps?.requestConfig?.serviceType === 'mock' &&
        isPlainObject(componentProps?.requestConfig?.mockData)
      ) {
        componentProps.requestConfig.formatResult = () => {
          return cloneDeep(componentProps?.requestConfig?.mockData?.data);
        };
      }
      if (componentProps?.searchRemote) {
        componentProps.filterLocal = false;
        if (componentProps?.searchKey && componentProps?.requestConfig) {
          componentProps.requestConfig.searchKey = componentProps.searchKey;
        }
      }
      if (componentProps?.requestConfig) {
        componentProps.requestConfig.throttleWait = 800;
        if (extraProps?.enableRemoteLazyLoad === true) {
          componentProps.enableRemoteLazyLoad = true;
          if (extraProps?.remoteLazyLoadKey) {
            componentProps.requestConfig.remoteLazyLoadKey =
              extraProps.remoteLazyLoadKey;
          }
        }

        // const execute = calculateRequestExecute(componentProps?.requestConfig, {
        //   [__formValue__]: recordDataSource,
        //   [__filterValue__]: recordDataSource,
        //   [__dataSource__]: state,
        // }, recordDataSource || {}, state)
        // if(execute === false) {
        //   componentProps.requestConfig.manual = true;
        // }
        handleFormUrlencodedContentType(componentProps.requestConfig);
      }

      if (componentProps?.requestWhenFocus === false) {
      } else {
        componentProps.onVisibleChange = visibleRun.bind(null, {
          requestConfig: componentProps?.requestConfig,
          state,
          recordDataSource,
        });
      }

      delete componentProps.searchRemote;
      delete componentProps.searchKey;
      delete componentProps.extraProps;
      delete componentProps.requestWhenFocus;
      componentProps.showSearch = true;
    } else {
      delete componentProps.requestConfig;
    }
  }
}

function handleSelectDataSource(config) {
  const { componentProps, state } = config || {};
  if (isPlainObject(componentProps)) {
    const { dataOrigin, dataSource } = componentProps;
    if (dataOrigin === 'static') {
      if (typeof dataSource === 'function') {
        try {
          const temp = dataSource(state);
          if (Array.isArray(temp)) {
            componentProps.dataSource = temp;
          }
        } catch (e) {}
      } else if (isValueObjectExpr(dataSource)) {
        const tempDs = calculateTextExprValue(dataSource, { state });
        if (Array.isArray(tempDs)) {
          componentProps.dataSource = tempDs;
        }
      }
      if (!Array.isArray(componentProps.dataSource)) {
        componentProps.dataSource = [];
      }
    }
  }
}

function calculateDataSource(config) {
  const { dataFrom, state, _context, _bindFilter } = config || {};
  let result;
  if (isPlainObject(dataFrom)) {
    const { dataOrigin, dataSource } = dataFrom;
    if (dataOrigin === dataOriginStatic) {
      if (Array.isArray(dataSource)) {
        result = dataSource;
      } else if (typeof dataSource === 'function') {
        try {
          const temp = dataSource(state);
          if (Array.isArray(temp)) {
            result = temp;
          }
        } catch (e) {}
      } else if (isValueObjectExpr(dataSource)) {
        const tempDs = calculateTextExprValue(dataSource, { state });
        if (Array.isArray(tempDs)) {
          result = tempDs;
        }
      }
    } else if (
      dataOrigin === dataOriginRequest &&
      isPlainObject(dataFrom?.requestConfig)
    ) {
      return makeRequest({
        buttonConfig: {
          options: {
            requestConfig: dataFrom?.requestConfig,
          },
        },
        recordDataSource: {},
        state,
        needSuccessToast: false,
        handleParams: () => {
          return {
            ...getFilterValue({
              filterConfig: {
                _bindFilter,
              },
              _context,
            }),
          };
        },
        extraParamList: [],
      });
    }
  }
  return result;
}

function isRecursionComponent(componentName) {
  return recursionComponentList.includes(componentName);
}

function handleOriginList(
  originList,
  labelKey,
  valueKey,
  groupExprName,
  extraConfig,
) {
  const result = [];
  const { dsName } = extraConfig || {};
  if (isArrayNotEmpty(originList)) {
    originList.forEach((item2) => {
      const { componentName } = item2;
      const label = handleI18nLabel(item2[labelKey]);
      const value = item2[valueKey];
      if (value) {
        const newLabel = label ? `${label}（${value}）` : value;
        const temp = {
          label: newLabel,
          text: newLabel,
          value: `${groupExprName}.${value}`,
        };
        if (
          componentName === 'RangePicker' ||
          componentName === 'RangeTimePicker'
        ) {
          temp.children = [
            {
              label: '开始时间',
              value: `${temp.value}[0]`,
            },
            {
              label: '结束时间',
              value: `${temp.value}[0]`,
            },
          ];
        }
        if (componentName === 'CnFormArrayCard' && item2?.name && dsName) {
          result.push({ ...temp });
          temp.label = `${temp.label} 的额外数据`;
          temp.children = [
            {
              label: tableCurrentRowLabel,
              value: `state.valueOf.${dsName}.${item2.name}.${__arrayTableCurrentRow__}`,
            },
          ];
        }
        result.push(temp);
        // if(handleComposeComponent && componentName === 'Compose') {
        //   const tempChildren = handleOriginList(item2?.options?.config, 'label','name',`${groupExprName}.${value}` )
        //   if(isArrayNotEmpty(tempChildren)) {
        //     result = [...result, ...tempChildren]
        //   }
        // }
      }
    });
  }
  return result;
}

function getNodeById(config) {
  const { field, id } = config;
  let result;
  if (id) {
    const nodesMap = field?.getNode?.()?.document?.nodesMap;
    if (nodesMap?.values()) {
      for (const item of nodesMap.values()) {
        if (item?.id === id) {
          result = item;
          break;
        }
      }
    }
  }
  return result;
}

function getArrayTableFieldList(param) {
  const { config, arrayTableName } = param || {};
  if (arrayTableName && isArrayNotEmpty(config)) {
    const result = [];
    config.forEach((item) => {
      const { label, name } = item || {};
      if (name) {
        const realLabel = handleI18nLabel(label) || name;
        result.push({
          label: realLabel,
          value: `${arrayTableName}.${__arrayTableCurrentRow__}.${name}`,
        });
      }
    });
    return result;
  }
}

function getDataSourceByName(name) {
  return VisualEngine?.context?.getManager?.('dataPool')?.getItemByName?.(name);
}

function removeDataSourceByNode(current) {
  if (current?.id) {
    const dataSourceName = current.getPropValue(_dataSourceName);
    if (dataSourceName) {
      const node = VisualEngine?.designer?.currentDocument?.nodesMap?.get?.(
        current.id,
      );
      if (!node) {
        const ds = getDataSourceByName(dataSourceName);
        if (ds && ds.id) {
          VisualEngine?.context?.getManager?.('dataPool')?.removeItem?.(ds.id);
        }
      }
    }
  }
}

function getFormDefaultValue(defaultParams, config) {
  const {
    urlParamsDataSource,
    state,
    position,
    isDesign,
    formConfig,
    getExtraParam,
    ignoreDefaultSelectFormRequest,
  } = config || {};
  const {
    dataOrigin,
    defaultValue = {},
    requestConfig = {},
    afterRequest = {},
  } = defaultParams || {};
  if (dataOrigin === 'static') {
    const result = calculateTextExprValue(defaultValue, {
      urlParamsDataSource,
      state,
    });
    if (result) {
      if (isPlainObject(result) && Object.keys(result).length > 0) {
        return result;
      } else if (
        isArrayNotEmpty(result) &&
        typeof defaultValue !== 'function'
      ) {
        const temp = {};
        const formItemFormatMap = {};
        const formItemComponentNameMap = {};
        const formItemMap = {};
        if (Array.isArray(formConfig)) {
          formConfig.forEach((item) => {
            const { name, componentName, options } = item;
            if (name && options?.outputFormat) {
              formItemFormatMap[name] = options.outputFormat;
            }
            formItemComponentNameMap[name] = componentName;
            formItemMap[name] = item;
          });
        }
        result.forEach((item) => {
          const { name, valueType, value } = item;
          if (name && valueType && value !== undefined) {
            if (valueType === 'buildIn') {
              if (isPlainObject(value)) {
                const time = calculateTime(value, formItemFormatMap[name], {
                  range: formItemComponentNameMap?.[name] === 'RangePicker',
                });
                if (time) {
                  temp[name] = time;
                }
              }
            } else if (valueType === 'DefaultSelect') {
              const current = formItemMap[name];
              if (
                allowSelectFirstComponentList.includes(current?.componentName)
              ) {
                const { options } = current || {};
                if (options?.dataOrigin === dataOriginStatic) {
                  const { dataSource } = options;
                  if (isArrayNotEmpty(dataSource)) {
                    if (typeof value === 'number') {
                      const tempDs = dataSource[value];
                      if (tempDs?.value !== undefined) {
                        temp[name] = tempDs.value;
                      }
                    }
                  }
                } else if (options?.dataOrigin === dataOriginRequest) {
                  if (
                    isEmptyButNotZero(temp[name]) &&
                    ignoreDefaultSelectFormRequest !== true
                  ) {
                    temp[name] = item;
                  }
                }
              }
            } else if (valueType === 'SelectFromDataSource') {
              temp[name] = calculateTextExprValue(value, {
                state,
              });
            } else {
              temp[name] = value;
            }
          }
        });
        if (Object.keys(temp).length > 0) {
          return temp;
        }
      }
    }
  } else if (dataOrigin === 'request') {
    const execute = calculateRequestExecute(
      requestConfig,
      {
        [__dataSource__]: state,
      },
      {},
      state,
    );
    if (execute === false) {
      return;
    }
    const realUrl = getRealRequestUrl({
      requestConfig,
      state,
      extraParam: getExtraParam?.(),
    });
    if (realUrl) {
      return makeRequest({
        buttonConfig: {
          options: {
            requestConfig: {
              ...requestConfig,
              url: realUrl,
              dynamicUrl: undefined,
            },
          },
        },
        urlParamsDataSource,
        recordDataSource: {},
        state,
        needSuccessToast: false,
        isDesign,
        getExtraParam,
      }).then((res) => {
        const res2 = getRealResponse(res);
        const { success, data } = res2;
        if (success) {
          if (isPlainObject(data) && Object.keys(data).length > 0) {
            return data;
          }
        }
      });
    }
  }
}

function getRealRequestUrl(config) {
  const { requestConfig, state, extraParam } = config || {};
  let result;
  if (requestConfig) {
    const { dynamicUrl, useDynamicUrl, url } = requestConfig;
    result = url;
    if (useDynamicUrl === true && typeof dynamicUrl === 'function') {
      const temp = executeFunction(dynamicUrl, state, extraParam || {});
      if (typeof temp === 'string') {
        result = temp;
      } else {
        result = '';
      }
    }
  }
  return result;
}

function isEmptyButNotZero(value) {
  return value === undefined || value === null || value === '';
}

function handleFormat(time, format) {
  if (time) {
    if (format) {
      return time.format(format);
    } else {
      return time?.valueOf();
    }
  }
  return time;
}

const transProxyToObject = (origin) => {
  const result = {};
  if (typeof origin === 'object') {
    const keys = Object.keys(origin);
    if (keys && keys.length > 0) {
      keys.forEach((key) => {
        result[key] = origin[key];
      });
    }
  }
  return result;
};

function calculateTime(value, format, config) {
  const { range } = config;
  if (isPlainObject(value)) {
    try {
      const { num, rela, time, unit } = value;
      if (rela && num !== undefined && unit) {
        let temp = dayjs()[rela](num, unit);
        if (temp) {
          if (range) {
            let start;
            let end;
            if (rela === 'subtract') {
              start = handleFormat(temp, format);
              end = handleFormat(dayjs(), format);
            } else if (rela === 'add') {
              start = handleFormat(dayjs(), format);
              end = handleFormat(temp, format);
            }
            return [start, end];
          } else if (time) {
            if (time !== 'now') {
              temp = temp[time]('d');
            }
            return handleFormat(temp, format);
          }
        }
      }
    } catch (e) {}
  }
}

function calculateWaitComponentList(config, defaultParams) {
  const result = {
    waitComponentList: [],
    waitComponentMap: {},
    configMap: {},
  };
  if (isArrayNotEmpty(config)) {
    config.forEach((item, index) => {
      const { name } = item || {};
      result.configMap[name] = item;
      const need = needRequestRemote(item, defaultParams);
      if (need) {
        result.waitComponentList.push(name);
        result.waitComponentMap[name] = need;
      }
    });
  }
  return result;
}

function needRequestRemote(config, defaultParams) {
  const { dataOrigin, defaultValue } = defaultParams || {};
  if (dataOrigin === dataOriginStatic && isArray(defaultValue)) {
    const { name, componentName, options } = config || {};
    if (name && allowSelectFirstComponentList.includes(componentName)) {
      const { dataOrigin, requestConfig } = options || {};
      if (dataOrigin === dataOriginRequest && requestConfig?.url) {
        const current = defaultValue.find(
          (item) => item?.name === name && item?.valueType === 'DefaultSelect',
        );
        if (current?.name) {
          return current;
        }
      }
    }
  }
  return false;
}

function executeEventWithoutJS(config) {
  const {
    eventType,
    events,
    _context,
    position,
    urlParamsDataSource,
    recordDataSource,
    jsParamList,
  } = config || {};
  if (eventType && Array.isArray(events) && events.length > 0) {
    for (const item of events) {
      const { name: eventName } = item;
      if (eventName === eventType) {
        const action = getButtonAction({ ...item, position });
        if (typeof action === 'function') {
          action({
            buttonConfig: {
              ...item,
              position,
              options: {
                ...item,
              },
            },
            position,
            state: _context?.state,
            urlParamsDataSource,
            recordDataSource,
            _context,
            jsParamList,
          });
        }
      }
    }
  }
}

function transDataSourceToMap(list) {
  const result = {};
  if (Array.isArray(list) && list.length > 0) {
    list.forEach((item) => {
      if (
        item.value !== undefined &&
        item.value !== null &&
        item.label !== undefined
      ) {
        result[item.value] = item.label;
      }
    });
  }
  return result;
}

function handleListI18nLabel(list, key) {
  if (isArrayNotEmpty(list)) {
    list?.forEach((item) => {
      if (item?.[key]) {
        item[key] = handleI18nLabel(item[key]);
      }
    });
  }
}

function isRequestConfig(requestConfig) {
  if (requestConfig) {
    const { url, serviceType } = requestConfig;
    if (url && serviceType) {
      return true;
    }
  }
  return false;
}

function renderIcon(type) {
  if (typeof type === 'string' && type.length > 0) {
    return <CnIcon type={type} />;
  }
  return undefined;
}

function setDataToDs(config) {
  const { data, _dataSourceName, _context, _dataSource } = config || {};
  if (isPlainObject(data) && _dataSourceName && _context) {
    _context?.setState({
      [_dataSourceName]: {
        ..._dataSource,
        ...data,
      },
    });
  }
}

function getArrayTableCurrentRowByField2(field) {
  if (field) {
    const segments = field?.path?.segments;
    const realSegments = segments.slice(0, -1);
    const currentRow = field?.form?.getValuesIn?.(realSegments);
    if (isPlainObject(currentRow)) {
      return currentRow;
    }
  }
}

function getDataSourceById(id) {
  return VisualEngine?.context?.getManager?.('dataPool')?.getItemById?.(id);
}

function createDataSource(dsConfig) {
  if (dsConfig) {
    const { id, name, description } = dsConfig;
    // const dataSourceList = getDataSourceList();
    if (id && name && VisualEngine) {
      const dataSource = VisualEngine?.context?.getManager('dataPool');
      return dataSource?.addItem({
        description,
        dpType: 'VALUE',
        id,
        initialData: '',
        isGlobal: false,
        name,
        protocal: 'VALUE',
      });
    }
  }
}

async function executeFlowList(config) {
  const result = [];
  const { list, position, _context } = config || {};
  if (isArrayNotEmpty(list) && _context) {
    for (const index in list) {
      const item = list[index];
      const { active, optType } = item || {};
      const isActive = executeObjectExpr(
        active,
        {
          [__dataSource__]: _context?.state,
        },
        {},
        _context?.state,
      );
      if (isActive === true) {
        const action = getButtonAction({
          ...item,
          position,
        });
        let flowResult;
        if (typeof action === 'function') {
          flowResult = await action({
            position,
            needSuccessToast: false,
            buttonConfig: { ...item },
            _context,
            state: _context?.state,
            urlParamsDataSource: _context?.state?.urlParams || {},
            recordDataSource: {},
          });
        }
        const handleFlowResult = getButtonItem(
          position,
          optType,
          'handleFlowResult',
        );
        if (typeof handleFlowResult === 'function') {
          flowResult = handleFlowResult(flowResult);
        }
        if (flowResult && _context) {
          let realIndex = +index;
          if (realIndex === 0) {
            realIndex = '';
          }
          _context.state.valueOf[optType + realIndex] = flowResult;
        }
        result.push(flowResult);
      }
    }
  }
  return result;
}

function clearState(config) {
  const { _context } = config || {};
  if (_context?.state) {
    const flowDataKeys = Object.keys(_context.state.valueOf);
    if (Array.isArray(flowDataKeys) && flowDataKeys.length > 0) {
      flowDataKeys.forEach((key) => {
        if (key?.includes(__stateValueOfSplit__)) {
        } else {
          // FIXME 需要将动作编排的临时存储数据清掉
          // _context.state.valueOf[key] = undefined;
        }
      });
    }
  }
}

function setAdvancedConfigToProps(props) {
  if (isPlainObject(props?.__advancedConfig__)) {
    Object.keys(props.__advancedConfig__).forEach((key) => {
      const tempV = props.__advancedConfig__[key];
      if (key && !isEmptyButNotZero(tempV)) {
        props[key] = tempV;
      }
    });
    delete props.__advancedConfig__;
  }
}

function batchCalculateTextExprValue(obj, config) {
  if (isPlainObject(obj)) {
    const result = {};
    for (const key in obj) {
      if (key && key.indexOf('_unsafe_MixedSetter') === -1) {
        const value = calculateTextExprValue(obj[key], config);
        if (key && value !== undefined) {
          result[key] = value;
        }
      }
    }
    return result;
  }
}

function handlePageDataSource(config) {
  const { componentProps, state } = config || {};
  if (isPlainObject(componentProps)) {
    const { dataOrigin, dataSource } = componentProps;
    if (dataOrigin === 'static') {
      if (typeof dataSource === 'function') {
        try {
          componentProps.dataSource = dataSource(state);
        } catch (e) {}
      } else if (isValueObjectExpr(dataSource)) {
        componentProps.dataSource = calculateTextExprValue(dataSource, {
          state,
        });
      }
    }
  }
}

// 计算请求是否执行
function calculateRequestExecute(requestConfig, ...arg) {
  if (requestConfig) {
    const originalExecute = requestConfig?.execute;
    const tempExecute = requestConfig?.__extraConfig__?.execute;
    if (
      isObjectExpr(tempExecute) ||
      typeof tempExecute === 'function' ||
      typeof tempExecute === 'boolean'
    ) {
      return executeObjectExpr(tempExecute, ...arg);
    } else if (typeof originalExecute === 'function') {
      return executeObjectExpr(originalExecute, ...arg);
    }
  }
}

function isObjectExpr(obj) {
  if (isPlainObject(obj) && obj.group && obj.param && obj.symbol) {
    return true;
  }
  return false;
}

function makeButtons(config) {
  const {
    buttons,
    _context,
    state,
    urlParamsDataSource,
    recordDataSource,
    extraParamList = [],
    formInstance,
    handleBtnProps,
    useProxyButton,
    arrayTableCurrentRow,
    arrayBaseField,
    arrayBaseFieldIndex,
    jsParamList,
  } = config;
  if (Array.isArray(buttons) && buttons.length > 0) {
    const result = [];
    for (const index in buttons) {
      const item = buttons[index];
      const {
        iconType,
        primaryKey,
        optType,
        options = {},
        children,
        position,
        hidden,
        disabled,
        getExtraParam,
        ...rest
      } = item;
      const isHidden = executeObjectExpr(
        hidden,
        {
          [__filterValue__]: recordDataSource || {},
          [__formValue__]: recordDataSource || {},
          [__dataSource__]: state,
          [__arrayTableCurrentRow__]: arrayTableCurrentRow,
        },
        recordDataSource || {},
        state,
        arrayBaseFieldIndex,
        formInstance?.values,
      );
      if (isHidden) {
        continue;
      }
      const isDisabled = executeObjectExpr(
        disabled,
        {
          [__filterValue__]: recordDataSource || {},
          [__formValue__]: recordDataSource || {},
          [__dataSource__]: state,
          [__arrayTableCurrentRow__]: arrayTableCurrentRow,
        },
        recordDataSource || {},
        state,
        arrayBaseFieldIndex,
        formInstance?.values,
      );
      const action = getButtonAction({ ...item, position });
      const componentDefine = getRunTimeItem({}, optType);
      const getRenderDom = getButtonItem(position, optType, 'getRenderDom');
      const btnProps = {
        ...rest,
      };
      if (isDisabled === true) {
        btnProps.disabled = isDisabled;
      }
      if (componentDefine?.component) {
        const component = getRealizeValue(componentDefine.component);
        if (component) {
          result.push(
            React.createElement(component, {
              children,
              ...btnProps,
              buttonConfig: item,
              _context,
              [_getFormValues]: () => {
                return formInstance?.values;
              },
              formInstance: undefined,
              arrayBaseField,
              arrayBaseFieldIndex,
            }),
          );
          continue;
        }
      } else if (typeof getRenderDom === 'function') {
        const dom = executeFunction(getRenderDom, {
          _context,
          buttonConfig: item,
          state,
          urlParamsDataSource,
          recordDataSource: {
            realize: () => {
              return formInstance?.values;
            },
          },
          btnProps,
        });
        if (dom) {
          result.push(dom);
          continue;
        }
      }
      if (action) {
        btnProps.onClick = action.bind(null, {
          buttonConfig: item,
          position,
          state,
          urlParamsDataSource,
          recordDataSource: {
            realize: () => {
              return formInstance?.values;
            },
          },
          formInstance,
          _context,
          getExtraParam,
          arrayTableCurrentRow,
          arrayBaseField,
          arrayBaseFieldIndex,
          jsParamList,
          ...extraParamList,
        });
      }
      if (typeof handleBtnProps === 'function') {
        handleBtnProps(btnProps);
      }
      const ButtonCom = CnButton;
      if (useProxyButton === true) {
      }
      result.push(
        <ButtonCom key={index} {...btnProps}>
          {renderIcon(iconType)}
          {children}
        </ButtonCom>,
      );
    }
    return result;
  }
  return null;
}

function makeALink(config) {
  const { linkExpr, _context, recordDataSource } = config || {};
  const { redirectType, text } = linkExpr;
  if (text) {
    const url = calculateUrl(linkExpr, {
      urlParamsDataSource: _context?.state?.urlParams || {},
      recordDataSource: {},
      state: _context?.state,
    });
    const extraProps = {};
    if (redirectType === 'open') {
      extraProps.target = '_blank';
    }
    if (url) {
      extraProps.href = url;
    }
    return (
      <a {...extraProps}>
        {calculateTextExprValue(text, {
          recordDataSource: recordDataSource || {},
          state: _context?.state,
        })}
      </a>
    );
  }
  return null;
}

function getFilterValue(config) {
  const { filterConfig, _context } = config || {};
  const { _bindFilter } = filterConfig || {};
  let result = {};
  if (isArrayNotEmpty(_bindFilter)) {
    for (const item of _bindFilter) {
      if (item) {
        const filterDom = _context?.$(item);
        const { _dataSourceName } = filterDom?.props || {};
        if (_dataSourceName) {
          result = {
            ...result,
            ...transProxyToObject(_context?.state?.[_dataSourceName]),
          };
        }
      }
    }
  }
  return result;
}

function dialogOpen(config) {
  const { dialogNodeId, data, _context } = config || {};
  if (dialogNodeId && typeof _context?.$ === 'function') {
    const dialogNode = _context.$(dialogNodeId);
    if (dialogNode) {
      return new Promise((resolve) => {
        setTimeout(() => {
          const p = dialogNode?.open?.(data);
          if (typeof p?.then === 'function') {
            p.then((res) => {
              setTimeout(() => {
                resolve(true);
              });
            });
          } else {
            setTimeout(() => {
              resolve(true);
            });
          }
        });
      });
    }
  }
}

function dialogClose(config) {
  const { dialogNodeId, data, _context } = config || {};
  if (dialogNodeId && typeof _context?.$ === 'function') {
    const dialogNode = _context.$(dialogNodeId);
    if (dialogNode) {
      return new Promise((resolve) => {
        setTimeout(() => {
          const p = dialogNode?.close?.(data);
          if (typeof p?.then === 'function') {
            p.then(() => {
              setTimeout(() => {
                resolve(true);
              });
            });
          } else {
            setTimeout(() => {
              resolve(true);
            });
          }
        });
      });
    }
  }
}

function tableLoad(config) {
  const { _bindTable, _context } = config || {};
  function reloadOneTable(id) {
    if (typeof id === 'string') {
      const table = _context?.$(id);
      table?.load?.();
    }
  }

  if (_bindTable && _context) {
    if (Array.isArray(_bindTable)) {
      _bindTable.forEach((item) => {
        reloadOneTable(item);
      });
    } else {
      reloadOneTable(_bindTable);
    }
  }
}


export {
  handleDesignMokelayUrl,
  handleSelectRequestConfig,
  handleSelectDataSource,
  getRealResponse,
  handleFormUrlencodedContentType,
  isRecursionComponent,
  getFlowListDataSource,
  handleOriginList,
  getNodeById,
  getArrayTableFieldList,
  removeDataSourceByNode,
  getFormDefaultValue,
  calculateTime,
  isEmptyButNotZero,
  getRealRequestUrl,
  transProxyToObject,
  calculateWaitComponentList,
  needRequestRemote,
  executeEventWithoutJS,
  getRunTimeBizComponent,
  transDataSourceToMap,
  handleListI18nLabel,
  isRequestConfig,
  renderIcon,
  setDataToDs,
  getArrayTableCurrentRowByField2,
  getDataSourceById,
  createDataSource,
  uuid,
  executeFlowList,
  clearState,
  setAdvancedConfigToProps,
  batchCalculateTextExprValue,
  handlePageDataSource,
  calculateRequestExecute,
  isObjectExpr,
  makeButtons,
  calculateDataSource,
  makeALink,
  getFilterValue,
  dialogOpen,
  dialogClose,
  tableLoad
};
