import { ButtonPosition } from '@/type/button-position';
import uniq from 'lodash/uniq';
import qs from 'query-string';
import * as cnUniApi from '@alife/cn-uni-api';
import {
  calculateTextExprValue,
  executeFunction,
  executeObjectExpr,
  getArrayTableFieldList,
  getBizComponent,
  getBizComponentNameList,
  getDataSourceList,
  getDataSourceListWithAllPath,
  getNodeById,
  getRealizeValue,
  getRealRequestUrl,
  getRealResponse,
  getRunTimeBizComponent,
  handleI18nLabel,
  handlePrototypeCondition,
  isArrayNotEmpty,
  isRecursionComponent,
  uuid,
} from '../util/util';
import {
  createServiceSelectPrototype,
  handleRequestParams,
  makeRequest,
} from './request';
import {
  createTableSelectSetters,
  getFormHandleTypeSetterSnippet,
  getSelectDialogSnippet,
  getSetterSnippet,
} from './setter-snippet';
import {
  getJSExpressionPrototype,
  getStyleListByPosition,
} from '@/common/manager/common-style';
import CheckboxSetter from '@/common/setter/checkbox-setter';
import ExprSetter from '@/common/setter/expr-setter';
import {
  __arrayTableCurrentRow__,
  __dataSource__,
  __flowData__,
  getCommonBoolDataSource,
} from '@/common/util/expr-const';
import isPlainObject from 'lodash/isPlainObject';
import { ActionRunEnv } from '@/type/action-run-env';
import { ParamSelectSetter } from '@/common/setter/param-select-setter';
import cloneDeep from 'lodash/cloneDeep';
import { pageDataSource } from '@/common/util/const';
import { CnDataSourceChange, emitEvent } from '@/common/util/event-name';
import { createMessageSetters } from '@/common/manager/message';
import isNumber from 'lodash/isNumber';
import { CnMessage } from '@cainiaofe/cn-ui-m';
import findLastIndex from 'lodash/findLastIndex';

const CnUniApi = window.cnUniApi || cnUniApi; // 兼容：优先用户script注入的cnUniApi
const { ActionSetter } = window.VisualEngineUtils || {};
const ALL_BUTTON_POSITION_LIST = Object.values(ButtonPosition);

const jsActionMap = {
  [ButtonPosition.navBarEvent]: `/**
* onBack
*
*/
function onBack(state) {

}`,
  [ButtonPosition.navBarRightButton]: `/**
* onClick
*
*/
function onClick(state) {

}`,
  [ButtonPosition.form]: `/**
* onClick
*
*/
function onClick({ form, state}) {

}`,
  [ButtonPosition.formDialog]: `/**
* onClick
*
*/
function onClick({ form, state}) {

}`,
};

const jsAction = {
  title: 'js脚本',
  value: 'jsAction',
  position: ALL_BUTTON_POSITION_LIST,
  getPrototypeList: (position, config) => {
    const { __field } = config || {};
    if (
      [
        ButtonPosition.navBarEvent,
        ButtonPosition.navBarRightButton,
        ButtonPosition.form,
        ButtonPosition.formDialog,
      ].includes(position)
    ) {
      let defaultActionName = 'onBack';
      if (
        [
          ButtonPosition.form,
          ButtonPosition.formDialog,
          ButtonPosition.navBarRightButton,
        ].includes(position)
      ) {
        defaultActionName = 'onClick';
      }
      return [
        {
          title: '自定义脚本',
          name: 'jsFunction',
          display: 'inline',
          className: 'cn-action-setter',
          setter: {
            componentName: <ActionSetter />,
            props: () => {
              const defaultCode = jsActionMap[position];
              return {
                supportTypes: ['page'],
                defaultCode,
                defaultActionName,
              };
            },
          },
        },
      ];
    }else {
      return [
        {
          title: '自定义脚本',
          name: 'jsFunction',
          // isRequired: true,
          // editable:true,
          display: 'inline',
          // condition(){
          //   return true;
          // },
          className: 'cn-action-setter',
          // setter: <ActionSetter
          //   supportTypes={['page']}
          //   defaultCode={defaultCode}
          //   defaultActionName={defaultActionName}
          // />,
          setter: {
            componentName: (
              <ActionSetter
                // supportTypes={['page']}
                // defaultCode={defaultCode}
                // defaultActionName={defaultActionName}
              />
            ),
            props: () => {
              const defaultCode = jsActionMap[position];
              const defaultActionName = 'jsAction';
              return {
                supportTypes: ['page'],
                defaultCode,
                defaultActionName,
              };
            },
          },
        },
      ];
    }
  },
  action: (config) => {
    const { buttonConfig, _context, position, jsParamList = [] } = config;
    const { name, options } = buttonConfig;
    const { jsFunction } = options || {};
    if (typeof jsFunction === 'function') {
      if (
        [
          ButtonPosition.navBarEvent,
          ButtonPosition.filterItemEvent,
          ButtonPosition.formItemEvent,
          ButtonPosition.formDialogItemEvent,
        ].includes(position)
      ) {
        if (name === 'onBack') {
          return jsFunction(...jsParamList);
        }
      } else if (
        [
          ButtonPosition.navBarRightButton,
          ButtonPosition.form,
          ButtonPosition.formDialog,
        ].includes(position)
      ) {
        return jsFunction(...jsParamList);
      }else {
        async function executeJsFunction() {
          await jsFunction();
        }
        return executeJsFunction();
      }
    }
  },
};

const link = {
  title: '跳转链接',
  value: 'link',
  position: ALL_BUTTON_POSITION_LIST,
  getDefaultProps: () => {
    return {
      redirectType: 'open',
      routerType: 'location',
    };
  },
  getPrototypeList: (position, config) => {
    let paramSetter = 'StringSetter';
    let urlSetter = 'StringSetter';
    const setterSnippet = getSetterSnippet({
      position,
      optType: 'link',
      ...config,
    });
    const { urlSetter: newUrlSetter, requestParamSetter } = setterSnippet || {};
    if (requestParamSetter) {
      paramSetter = requestParamSetter;
    }
    if (newUrlSetter) {
      urlSetter = newUrlSetter;
    }
    return [
      {
        title: '路由类型',
        name: 'routerType',
        condition() {
          return false;
        },
        originalCondition() {
          return false;
        },
        description: '路由类型',
        setter: 'StringSetter',
      },
      {
        title: '链接地址',
        name: 'url',
        // condition: {
        //   "type": "JSFunction",
        //   "value": "() => false"
        // },
        description: '链接地址',
        className: 'cn-link-url-setter',
        setter: urlSetter,
      },
      {
        title: '打开方式',
        name: 'redirectType',
        description: '打开方式',
        setter: {
          componentName: 'RadioGroupSetter',
          initialValue: 'current',
          props: {
            options: [
              {
                title: '当前页面',
                value: 'current',
              },
              {
                title: '新开页面',
                value: 'open',
              },
            ],
          },
        },
      },
      {
        title: 'url参数',
        name: 'urlParams',
        description: 'url参数',
        // extraProps: {
        // },
        className: 'cn-button-url-param-setter',
        setter: {
          componentName: 'ArraySetter',
          props: {
            mode: 'list',
            itemSetter: {
              componentName: 'ObjectSetter',
              // initialValue: {
              //   "type": "JSFunction",
              //   "value": "() => {return {primaryKey: String(Math.floor(Math.random() * 10000)),children: \"Title\",optType:\"link\"               };}"
              // },
              initialValue: {
                label: 'param',
              },
              props: {
                config: {
                  items: [
                    {
                      title: '参数名',
                      name: 'label',
                      isRequired: true,
                      description: '参数名',
                      setter: 'StringSetter',
                    },
                    // {
                    //   title: '参数值',
                    //   name: 'value',
                    //   isRequired: true,
                    //   description: '参数值',
                    //   supportVariable: true,
                    //   setter: 'StringSetter',
                    // },
                    {
                      title: '参数值',
                      name: 'value',
                      isRequired: true,
                      description: '参数值',
                      // supportVariable: true,
                      className: 'cn-param-select-setter',
                      setter: paramSetter,
                    },
                  ],
                },
              },
            },
          },
        },
      },
    ];
  },
  action: (config, extra) => {
    const {
      buttonConfig,
      urlParamsDataSource,
      recordDataSource: originalRecordDataSource,
      state,
      position,
      arrayTableConfig,
      selectedRowKeys = [],
      selectedRowRecords = [],
    } = config;
    const needDelay =
      position === ButtonPosition.formDialogSubmitAfterRequestSuccess ||
      position === ButtonPosition.formSubmitAfterRequestSuccess;
    const { options } = buttonConfig || {};
    let extraParamList = [];
    let recordDataSource = getRealizeValue(originalRecordDataSource);
    if (position === ButtonPosition.arrayTableOperate) {
      if (extra?.field) {
        const { field } = extra;
        const { formItemConfig } = arrayTableConfig || {};
        if (formItemConfig?.name && field) {
          const list = field?.query?.(formItemConfig?.name)?.value?.();
          if (Array.isArray(list) && list[field?.index]) {
            recordDataSource = list[field.index];
            extraParamList = [field.index];
          }
        }
      }
    } else {
      extraParamList.push(selectedRowKeys);
      extraParamList.push(selectedRowRecords);
    }
    if (options) {
      const { url, redirectType, urlParams = [] } = options;
      let search = '';
      if (urlParams && urlParams.length > 0) {
        const temp = handleRequestParams(urlParams, {
          urlParamsDataSource,
          recordDataSource,
          state,
          extraParamList,
        });
        search = qs.stringify(temp);
      }
      if (url) {
        let realUrl = calculateTextExprValue(url, {
          urlParamsDataSource,
          recordDataSource,
          state,
          extraParamList,
        });
        if (typeof realUrl === 'string' && realUrl.length > 0) {
          if (realUrl.indexOf('?') !== -1) {
            realUrl += `&${search}`;
          } else if (search) {
            realUrl += `?${search}`;
          }
          const temp = () => {
            if (redirectType === 'current') {
              if (typeof window.jumpTo === 'function') {
                const tempList = realUrl?.split('?');
                window.jumpTo({
                  pathname: tempList?.[0],
                  search: tempList?.[1],
                });
              } else {
                location.href = realUrl;
              }
            } else if (redirectType === 'open') {
              if (typeof window.jumpTo === 'function') {
                const tempList = realUrl?.split('?');
                window.jumpTo({
                  pathname: tempList?.[0],
                  search: tempList?.[1],
                  type: '_blank',
                });
              } else {
                window.open(realUrl);
              }
            }
          };
          if (needDelay) {
            setTimeout(temp, 1500);
          } else {
            temp();
          }
        }
      }
    }
  },
  // getButtonNode: (arg) => {
  //   const { buttonConfig, record, index } = arg;
  //   const { optType, options = {}, children } = buttonConfig;
  //   if (children) {
  //     let events = {};
  //     if (optType) {
  //       const button = componentMap[optType];
  //       if (typeof button?.action === 'function') {
  //         events = {
  //           onClick: button.action.bind(this, arg),
  //         };
  //       }
  //     }
  //     return <span {...events}>{children}</span>;
  //   }
  //   return null;
  // },
};

const message = {
  title: '提示信息（toast）',
  value: 'message',
  position: ALL_BUTTON_POSITION_LIST,
  getPrototypeList: (position, config) => {
    return createMessageSetters({ position, isToast: true, config });
  },
  action: (config) => {
    const {
      buttonConfig,
      urlParamsDataSource,
      state,
      _context,
      recordDataSource,
      actionRunEnv,
      getFlowActionInfo,
      position,
    } = config || {};
    let { response = {} } = config || {};
    if (ActionRunEnv.flowAction === actionRunEnv) {
      const flowInfo = getFlowActionInfo?.();
      const { flowList, currentFlowIndex } = flowInfo || {};
      if (isArrayNotEmpty(flowList) && currentFlowIndex) {
        const realIndex = +currentFlowIndex;
        if (isNumber(realIndex) && !isNaN(realIndex)) {
          const beforeList = flowList.slice(0, realIndex);
          // const lastRequestIndex = beforeList.findLastIndex(item=>item?.optType === 'request');
          const lastRequestIndex = findLastIndex(
            beforeList,
            (item) => item?.optType === 'request',
          );
          let path = 'request';
          if (lastRequestIndex !== 0) {
            path += lastRequestIndex;
          }
          const realResponse = state?.valueOf?.[path];
          if (isPlainObject(realResponse)) {
            response = realResponse;
          }
        }
      }
    }

    const msg = response?.msg;
    const { options = {} } = buttonConfig || {};
    const { type, title, content, ...rest } = options;
    let realContent = content;
    const realType =
      calculateTextExprValue(type, {
        urlParamsDataSource,
        recordDataSource: getRealizeValue(recordDataSource),
        state,
      }) || 'success';
    if (typeof content === 'function') {
      let realFirstParam = response;
      if (
        [
          ButtonPosition.formItemEvent,
          ButtonPosition.formDialogItemEvent,
        ].includes(position)
      ) {
        realFirstParam = getRealizeValue(recordDataSource);
      }
      realContent = content(realFirstParam, state);
    }
    if (!realContent && !title) {
      realContent = msg;
    }
    CnMessage?.[realType]?.({ title, content: realContent, ...rest });
  },
};

const submit = {
  title: '提交（先校验表单，再发请求）',
  value: 'submit',
  position: [ButtonPosition.formDialog, ButtonPosition.form],
  getPrototypeList: (position) => {
    let paramSetter = 'StringSetter';
    let paramSelectSetter;
    let jsExpressionSetter;
    const setterSnippet = getSetterSnippet({
      position,
      optType: 'submit',
    });
    const { requestParamSetter } = setterSnippet || {};
    if (requestParamSetter) {
      paramSetter = requestParamSetter;
      if (Array.isArray(requestParamSetter?.props?.setters)) {
        paramSelectSetter = requestParamSetter?.props?.setters?.find(
          (item) => item?.componentName === 'ParamSelectSetter',
        );
        jsExpressionSetter = requestParamSetter?.props?.setters?.find(
          (item) => item?.componentName === 'CnRowDataSetter',
        );
      }
    }
    const result = [
      ...createServiceSelectPrototype({
        optType: 'submit',
        paramSetter,
        position,
        paramSelectSetter,
        jsExpressionSetter,
        paramTitleDom: (
          <div>
            请求参数配置{' '}
            <span
              style={{ fontWeight: 'bold', color: 'red', marginLeft: '30px' }}
            >
              提示：提交时会默认带上当前表单的全部数据作为参数，无需手动配置
            </span>
          </div>
        ),
      }),
    ];
    if ([ButtonPosition.formDialog].includes(position)) {
      result.push({
        name: 'afterRequestNotCloseDialog',
        title: '请求成功后不关闭弹窗',
        setter: 'BoolSetter',
      });
    }
    return result;
  },
  action: (config) => {
    const {
      buttonConfig,
      formInstance,
      position,
      close,
      urlParamsDataSource,
      recordDataSource,
      state,
      _context,
      dialogRef,
      needSuccessToast: paramNeedSuccessToast,
      getExtraParam,
    } = config;
    const realFormInstance = getRealizeValue(formInstance);
    if (buttonConfig && realFormInstance) {
      if (realFormInstance?.submitting) {
      } else {
        let afterRequestPosition;
        if (ButtonPosition.formDialog === position) {
          afterRequestPosition =
            ButtonPosition.formDialogSubmitAfterRequestSuccess;
        } else if (ButtonPosition.form === position) {
          afterRequestPosition = ButtonPosition.formSubmitAfterRequestSuccess;
        }
        const { options } = buttonConfig || {};
        const {
          afterRequest = {},
          requestConfig = {},
          afterRequestNotCloseDialog,
        } = options || {};
        const realUrl = getRealRequestUrl({
          requestConfig,
          state,
          extraParam: getExtraParam?.(),
        });
        if (realUrl) {
          requestConfig.url = realUrl;
          requestConfig.dynamicUrl = undefined;
          requestConfig.useDynamicUrl = undefined;
          return realFormInstance?.submit((value) => {
            if (value) {
              let needSuccessToast = true;
              if (paramNeedSuccessToast !== undefined) {
                needSuccessToast = paramNeedSuccessToast;
              }
              if (afterRequestPosition && afterRequest?.optType === 'message') {
                needSuccessToast = false;
              }
              return makeRequest({
                buttonConfig,
                urlParamsDataSource,
                recordDataSource: value,
                state,
                needSuccessToast,
                getExtraParam,
                handleParams: () => {
                  return value;
                },
                onCancel: () => {
                  if (realFormInstance?.setSubmitting) {
                    realFormInstance.setSubmitting(false);
                  }
                },
                extraParamList: [],
              })
                .then((res) => {
                  if (afterRequestNotCloseDialog !== true) {
                    close && close();
                  }
                  return res;
                })
                .finally((res) => {
                  if (realFormInstance?.setSubmitting) {
                    realFormInstance.setSubmitting(false);
                  }
                });
            }
          });
        } else {
          return realFormInstance?.validate?.();
        }
      }
    }
  },
};

const reset = {
  title: '重置',
  value: 'reset',
  position: [ButtonPosition.formDialog, ButtonPosition.form],
  action: (config) => {
    const { buttonConfig, formInstance, position } = config;
    const realFormInstance = getRealizeValue(formInstance);
    if (buttonConfig && realFormInstance) {
      realFormInstance.reset('*');
    }
  },
};

const setFormValue = {
  title: '给表单设置数据',
  value: 'setFormValue',
  position: ALL_BUTTON_POSITION_LIST,
  getDefaultProps: () => {
    return {
      mode: 'merge',
    };
  },
  getPrototypeList: (position, config) => {
    const { flowList, currentFlowIndex } = config || {};
    return [
      ...createFormSelectSetters({
        mode: 'single',
      }),
      getFormHandleTypeSetterSnippet(),
      // {
      //   name:'mode',
      //   title:'新数据填入表单的方式',
      //   setter: {
      //     componentName: 'RadioGroupSetter',
      //     props: {
      //       options: [
      //         {
      //           title: '和原表单值合并',
      //           value: 'merge',
      //         },
      //         {
      //           title: '清空表单重新设值',
      //           value: 'overwrite',
      //         },
      //       ],
      //     },
      //   },
      // },
      {
        name: 'formValues',
        title: '要填入表单的数据',
        className: 'cn-button-url-param-setter',
        condition(prop) {
          return (
            prop?.parent?.getPropValue?.('handleType') === 'setFormFieldValue'
          );
        },
        originalCondition(prop) {
          return (
            prop?.parent?.getPropValue?.('handleType') === 'setFormFieldValue'
          );
        },
        setter: {
          title: '给表单每个字段设置数据',
          componentName: 'ArraySetter',
          props: {
            mode: 'list',
            itemSetter: {
              componentName: 'ObjectSetter',
              // initialValue: {
              // },
              props: {
                config: {
                  items: [
                    {
                      name: 'label',
                      display: 'inline',
                      title: '选择字段',
                      isRequired: true,
                      setter: {
                        componentName: 'CnTreeSelectSetter',
                        props: (field) => {
                          const dataSource = [];
                          const currentData =
                            field?.parent?.parent?.parent?.getValue?.();
                          const { _bindForm } = currentData || {};
                          if (_bindForm && field) {
                            const node = getNodeById({
                              field,
                              id: _bindForm,
                            });
                            if (node?.id) {
                              const config = node?.getPropValue?.('config');
                              if (Array.isArray(config) && config.length > 0) {
                                config.forEach((item) => {
                                  if (item?.name) {
                                    const temp = {
                                      label:
                                        handleI18nLabel(item?.label) ||
                                        item.name,
                                      value: item.name,
                                    };
                                    dataSource.push(temp);
                                    if (
                                      isRecursionComponent(item?.componentName)
                                    ) {
                                      const children = getArrayTableFieldList({
                                        config: item?.options?.config,
                                        arrayTableName: item.name,
                                      });
                                      if (isArrayNotEmpty(children)) {
                                        temp.children = children;
                                      }
                                    }
                                  }
                                });
                              }
                            }
                          }
                          return {
                            dataSource,
                            popupClassName: 'cn-tree-select-setter-pupup',
                          };
                        },
                      },
                    },
                    {
                      name: 'value',
                      display: 'inline',
                      title: '数据',
                      isRequired: true,
                      className: 'cn-param-select-setter',
                      setter: {
                        componentName: 'MixedSetter',
                        props: {
                          setters: [
                            {
                              componentName: 'ParamSelectSetter',
                              props: {
                                ParamSelectSetterComponent: ParamSelectSetter,
                                configList: [
                                  {
                                    groupName: '其他数据',
                                    groupExprName: __dataSource__,
                                    needSecondParam: true,
                                  },
                                  {
                                    groupName: '动作编排的数据',
                                    groupExprName: __flowData__,
                                    needSecondParam: true,
                                    flowList,
                                    currentFlowIndex,
                                  },
                                ],
                              },
                              title: '从数据源选择',
                            },
                            getJSExpressionPrototype({
                              type: 'formRequest',
                              prototypeConfig: config,
                            }),
                          ],
                        },
                      },
                    },
                  ],
                },
              },
            },
          },
        },
      },
      {
        name: 'allFormValues',
        display: 'inline',
        condition(prop) {
          return (
            prop?.parent?.getPropValue?.('handleType') === 'setAllFormValue'
          );
        },
        originalCondition(prop) {
          return (
            prop?.parent?.getPropValue?.('handleType') === 'setAllFormValue'
          );
        },
        title: '新的表单数据',
        className: 'cn-param-select-setter',
        // className: 'cn-button-url-param-setter',
        setter: {
          componentName: 'MixedSetter',
          props: {
            setters: [
              {
                componentName: 'ParamSelectSetter',
                props: {
                  configList: [
                    {
                      groupName: '其他数据',
                      groupExprName: __dataSource__,
                      needSecondParam: true,
                    },
                    {
                      groupName: '动作编排的数据',
                      groupExprName: __flowData__,
                      needSecondParam: true,
                      flowList,
                      currentFlowIndex,
                    },
                  ],
                },
                title: '从数据源选择',
              },
              {
                componentName: 'StringSetter',
                title: '字符串',
              },
              {
                componentName: 'NumberSetter',
                title: '数字',
              },
              getJSExpressionPrototype({
                type: 'formRequest',
                prototypeConfig: config,
              }),
            ],
          },
        },
      },
    ];
  },
  action: (config) => {
    const {
      buttonConfig,
      urlParamsDataSource,
      state,
      _context,
      field,
      position,
      arrayBaseFieldIndex,
    } = config || {};
    const { options } = buttonConfig || {};
    const { formValues, _bindForm, handleType, allFormValues } = options || {};
    if (_bindForm) {
      const formNode = _context?.$(_bindForm);
      const formInstance = formNode?.getFormInstance?.();
      if (formInstance) {
        const oldFormValue = cloneDeep(formInstance?.values);
        if (handleType === 'clearFormValue') {
          formInstance.setValues?.({}, 'overwrite');
        } else if (handleType === 'setAllFormValue') {
          const newFormValue = calculateTextExprValue(allFormValues, {
            urlParamsDataSource,
            recordDataSource: oldFormValue,
            state,
          });
          if (isPlainObject(newFormValue)) {
            formInstance.setValues?.(newFormValue, 'overwrite');
          }
        } else {
          let newFormValue;
          if (Array.isArray(formValues)) {
            if (formValues.length > 0) {
              const arrayTableValues = [];
              const notArrayTableValues = [];
              formValues.forEach((item) => {
                if (item?.label?.includes(__arrayTableCurrentRow__)) {
                  arrayTableValues.push(item);
                } else {
                  notArrayTableValues.push(item);
                }
              });
              const temp = handleRequestParams(notArrayTableValues, {
                urlParamsDataSource,
                recordDataSource: oldFormValue || {},
                state,
              });
              if (isArrayNotEmpty(arrayTableValues)) {
                let fieldIndex;
                if (position === ButtonPosition.arraySubAreaCardOperate) {
                  fieldIndex = arrayBaseFieldIndex;
                } else if (field) {
                  fieldIndex = field?.path?.segments?.[1];
                }
                if (typeof fieldIndex === 'number') {
                  const tempFormValue = { ...oldFormValue, ...temp };
                  arrayTableValues.forEach((aitem) => {
                    const { label, value } = aitem || {};
                    const arr = label?.split?.(`.${__arrayTableCurrentRow__}.`);
                    if (arr.length === 2) {
                      const fieldName = arr[0];
                      const arrayTableFieldName = arr[1];
                      const temp2 = handleRequestParams([aitem], {
                        urlParamsDataSource,
                        recordDataSource: tempFormValue,
                        state,
                      });
                      if (
                        fieldName &&
                        arrayTableFieldName &&
                        tempFormValue[fieldName]?.[fieldIndex]
                      ) {
                        tempFormValue[fieldName][fieldIndex][
                          arrayTableFieldName
                        ] = temp2[label];
                        temp[fieldName] = tempFormValue[fieldName];
                      }
                    }
                  });
                }
              }
              if (isPlainObject(temp)) {
                newFormValue = temp;
              }
            }
          }
          formInstance.setValues?.(newFormValue);
        }
      }
    }
    return Promise.resolve();
  },
};

const arrayTableAdd = {
  title: '添加一行',
  value: 'arrayTableAdd',
  position: [ButtonPosition.arrayTableOperate],
  getPrototypeList: (position) => {
    return [];
  },
  action: ({ buttonConfig, formData, open, close }) => {},
};

const flowAction = {
  title: '动作编排',
  value: 'flowAction',
  position: ALL_BUTTON_POSITION_LIST,
  getPrototypeList: (position) => {
    return [
      {
        name: 'flowList',
        title: '动作编排',
        display: 'plain',
        setter: createFlowListSetters({
          position,
          activeSetter: {
            componentName: 'MixedSetter',
            props: {
              setters: [
                {
                  componentName: <CheckboxSetter />,
                  title: '启用/禁用',
                },
                {
                  componentName: (
                    <ExprSetter
                    // configList={[
                    //   {
                    //     groupName:'其他数据',
                    //     groupExprName: __dataSource__,
                    //     needSecondParam:true,
                    //   }
                    // ]}
                    />
                  ),
                  props(field) {
                    const flowList = field?.parent?.parent?.getValue?.();
                    const index = field?.parent?.name;
                    return {
                      configList: [
                        {
                          groupName: '动作编排的数据',
                          groupExprName: __flowData__,
                          needSecondParam: true,
                          flowList,
                          currentFlowIndex: index,
                        },
                        {
                          groupName: '其他数据',
                          groupExprName: __dataSource__,
                          needSecondParam: true,
                        },
                      ],
                    };
                  },
                  title: '简单表达式',
                },
                {
                  title: '写js表达式',
                  componentName: 'CnRowDataSetter',
                  props(field) {
                    const stateList = getDataSourceListWithAllPath({
                      needChildren: true,
                      prototypeConfig: {
                        flowList: field?.parent?.parent?.getValue?.(),
                        currentFlowIndex: field?.parent?.name,
                      },
                    });
                    return {
                      list: stateList,
                      initialCode: `(arg, state) => {
  // return state.urlParams.xxx;
}`,
                      tip: `
state：全部的数据，在左侧列表中选择使用。
`,
                    };
                  },
                },
              ],
            },
          },
        }),
      },
    ];
  },
  action: (config, ...otherArgs) => {
    const { buttonConfig, position, _context } = config || {};
    const { options } = buttonConfig || {};
    const { flowList } = options;

    if (Array.isArray(flowList) && flowList.length > 0) {
      async function executeFlowList(list) {
        const result = [];
        for (const index in list) {
          const item = list[index];
          const { active, optType, options: itemOptions } = item || {};
          const isActive = executeObjectExpr(
            active,
            {
              [__dataSource__]: _context?.state,
            },
            {},
            _context?.state,
          );
          if (isActive === true) {
            let action = getButtonAction({
              ...item,
              position,
            });
            if (!action) {
              const componentDefine = getRunTimeItem(optType);
              const component = getRealizeValue(componentDefine?.component);

              if (typeof component?.action === 'function') {
                action = component.action;
              }
            }
            let flowResult;
            if (typeof action === 'function') {
              flowResult = await action(
                {
                  needSuccessToast: false,
                  ...config,
                  buttonConfig: { ...item },
                  // 动作执行的环境
                  actionRunEnv: 'flowAction',
                  getFlowActionInfo: () => {
                    return {
                      flowList,
                      currentFlowIndex: index,
                    };
                  },
                },
                ...otherArgs,
              );
            }
            const handleFlowResult = getItem(
              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;
      }
      if (_context?.state) {
        const flowDataKeys = Object.keys(_context.state.valueOf);
        if (Array.isArray(flowDataKeys) && flowDataKeys.length > 0) {
          flowDataKeys.forEach((key) => {
            if (key) {
              if (key.includes('$$$') || key.startsWith('Cn')) {
              } else {
                _context.state.valueOf[key] = undefined;
              }
            }
          });
        }
      }
      executeFlowList(flowList);
      // try {
      // }catch (e){
      //   console.log('flow action run error', e);
      // }
    }
  },
};

const request = {
  title: '发请求',
  value: 'request',
  position: ALL_BUTTON_POSITION_LIST,
  getPrototypeList: (position, config) => {
    let paramSetter = 'StringSetter';
    let paramSelectSetter;
    let jsExpressionSetter;
    let wholeParamSetter;
    const setterSnippet = getSetterSnippet({
      position,
      optType: 'request',
      ...config,
    });
    const { requestParamSetter } = setterSnippet || {};
    if (requestParamSetter) {
      paramSetter = requestParamSetter;
      if (Array.isArray(requestParamSetter?.props?.setters)) {
        paramSelectSetter = requestParamSetter?.props?.setters?.find(
          (item) => item?.componentName === 'ParamSelectSetter',
        );
        jsExpressionSetter = requestParamSetter?.props?.setters?.find(
          (item) => item?.componentName === 'CnRowDataSetter',
        );
      }
    }
    if ([ButtonPosition.tableOperate].includes(position)) {
      wholeParamSetter = {
        name: 'params',
        title: '请求参数配置',
        className: 'params-list',
        setter: {
          componentName: 'MixedSetter',
          props: {
            setters: [
              {
                title: '设置每个字段的值',
                componentName: 'ArraySetter',
                props: {
                  mode: 'list',
                  itemSetter: {
                    componentName: 'ObjectSetter',
                    initialValue: {},
                    props: {
                      config: {
                        items: [
                          {
                            name: 'label',
                            isRequired: true,
                            title: '参数名',
                            setter: 'StringSetter',
                          },
                          {
                            name: 'value',
                            isRequired: true,
                            title: '参数值',
                            setter: paramSetter,
                          },
                        ],
                      },
                    },
                  },
                },
              },
              jsExpressionSetter,
            ],
          },
        },
      };
    }
    return createServiceSelectPrototype({
      optType: 'request',
      paramSetter,
      position,
      paramSelectSetter,
      jsExpressionSetter,
      wholeParamSetter,
    });
  },
  action: (config, extra) => {
    let {
      buttonConfig = {},
      record,
      componentProps = {},
      position,
      tableRef,
      state,
      urlParamsDataSource,
      recordDataSource,
      needSuccessToast,
      extraParamList,
      arrayTableConfig,
      noNeedHandleResult,
      isDesign,
      _context,
      field,
      formInstance,
      actionRunEnv,
      getExtraParam,
      arrayTableCurrentRow,
      arrayBaseFieldIndex,
    } = config;
    const { options = {} } = buttonConfig;
    const { keepPagination } = options;

    if (position === ButtonPosition.arraySubAreaCardOperate) {
      recordDataSource = arrayTableCurrentRow;
      extraParamList = [arrayBaseFieldIndex];
    } else if (position === ButtonPosition.arrayTableOperate) {
      if (extra?.field) {
        const { field } = extra;
        const { formItemConfig } = arrayTableConfig || {};
        if (formItemConfig?.name && field) {
          const list = field?.query?.('..')?.value?.();
          if (Array.isArray(list) && list[field?.index]) {
            recordDataSource = list[field.index];
            if (!extraParamList) {
              extraParamList = [field.index];
            }
          }
        }
      }
    }
    const realField = field || extra?.field;
    return makeRequest({
      buttonConfig,
      urlParamsDataSource,
      recordDataSource: getRealizeValue(recordDataSource),
      state,
      needSuccessToast,
      noNeedHandleResult,
      extraParamList,
      position,
      isDesign,
      _context,
      getExtraParam: () => {
        const tempExtraParam = executeFunction(getExtraParam);
        let extraParam = {};
        if (isPlainObject(tempExtraParam)) {
          extraParam = {
            ...tempExtraParam,
          };
        }
        // const realFormInstance = getRealizeValue(formInstance);
        // if(realFormInstance && field && position === ButtonPosition.formItemEvent) {
        //   const tempFormValue = realFormInstance.values;
        //   if(tempFormValue) {
        //     const segments = field?.path?.segments;
        //     if(isArrayNotEmpty(segments) && segments.length >= 3) {
        //       const needSegments = segments.slice(0,2)
        //       const tempCurrentRow = get(tempFormValue, needSegments)
        //       if(isPlainObject(tempCurrentRow)) {
        //         extraParam[__arrayTableCurrentRow__] = tempCurrentRow;
        //       }
        //     }
        //
        //   }
        // }
        const realFormInstance = getRealizeValue(formInstance);
        if (
          realFormInstance &&
          realField &&
          [
            ButtonPosition.formItemEvent,
            ButtonPosition.arraySubAreaCardOperate,
          ].includes(position)
        ) {
          const realPath = field?.path?.parent?.()?.segments;
          if (ButtonPosition.arraySubAreaCardOperate === position) {
          }
          const tempCurrentRow = realFormInstance?.getValuesIn?.(
            field?.path?.parent?.()?.segments,
          );
          if (isPlainObject(tempCurrentRow)) {
            extraParam[__arrayTableCurrentRow__] = tempCurrentRow;
          }
        }
        return extraParam;
      },
      handleParams: () => {
        const params = {};
        if (position === ButtonPosition.tableOperate) {
          const { primaryKey } = componentProps;
          if (primaryKey && record[primaryKey] !== undefined) {
            params[primaryKey] = record[primaryKey];
          }
        }
        return params;
      },
    }).then((res) => {
      if (position !== ButtonPosition.tableToolArea) {
        if (actionRunEnv === ActionRunEnv.flowAction) {
        } else if (position === ButtonPosition.tableOperate) {
          if (keepPagination === true) {
            tableRef?.tableLoad()?.();
          } else {
            tableRef?.load?.();
          }
        } else {
          tableRef?.load?.();
        }
      }
      return res;
    });
  },
  handleFlowResult: (res) => {
    return getRealResponse(res);
  },
  // getButtonNode: (arg) => {
  //   const { buttonConfig, record, index } = arg;
  //   const { optType, options = {}, children } = buttonConfig;
  //   if (children) {
  //     let events = {};
  //     if (optType) {
  //       const { needConfirm, confirmInfo = {} } = options;
  //       const button = componentMap[optType];
  //       if (typeof button?.action === 'function') {
  //         const action = button.action.bind(this, arg);
  //         events = {
  //           onClick: needConfirm ? () => {
  //             Dialog.confirm({
  //               v2: true,
  //               title: confirmInfo.title || '通知',
  //               content: confirmInfo.content || '是否确认',
  //               onOk: action,
  //               cancelProps: {
  //                 children: '关闭弹框',
  //               },
  //             });
  //           } : action,
  //         };
  //       }
  //     }
  //     return <span {...events}>{children}</span>;
  //   }
  //   return null;
  // },
};

const arrayTableRemove = {
  title: '删除',
  value: 'arrayTableRemove',
  position: [ButtonPosition.arrayTableOperate],
  action: (config) => {},
};

const setDataSourceValue = {
  title: '给页面的数据源设置数据',
  value: 'setDataSourceValue',
  position: ALL_BUTTON_POSITION_LIST,
  getDefaultProps: () => {
    return {};
  },
  getPrototypeList: (position, config) => {
    const { flowList, currentFlowIndex } = config || {};
    return [
      {
        name: 'dataSourceValues',
        title: '给数据源设置数据',
        className: 'cn-button-url-param-setter',
        setter: {
          componentName: 'MixedSetter',
          props: {
            setters: [
              {
                title: '给数据源设置数据',
                componentName: 'ArraySetter',
                props: {
                  mode: 'list',
                  itemSetter: {
                    componentName: 'ObjectSetter',
                    // initialValue: {
                    // },
                    props: {
                      config: {
                        items: [
                          {
                            name: 'label',
                            display: 'inline',
                            title: '选择页面数据源',
                            isRequired: true,
                            setter: {
                              componentName: 'SelectSetter',
                              props: (field) => {
                                const options = getDataSourceList({
                                  typeList: ['VALUE'],
                                })?.filter(
                                  (item) =>
                                    item?.dataSourceId &&
                                    item.dataSourceId?.startsWith?.(
                                      pageDataSource,
                                    ),
                                );
                                return {
                                  options: options || [],
                                };
                              },
                            },
                          },
                          {
                            name: 'value',
                            display: 'inline',
                            title: '数据',
                            isRequired: true,
                            className: 'cn-param-select-setter',
                            setter: {
                              componentName: 'MixedSetter',
                              props: {
                                setters: [
                                  {
                                    componentName: 'ParamSelectSetter',
                                    props: {
                                      configList: [
                                        {
                                          groupName: '其他数据',
                                          groupExprName: __dataSource__,
                                          needSecondParam: true,
                                        },
                                        {
                                          groupName: '动作编排的数据',
                                          groupExprName: __flowData__,
                                          needSecondParam: true,
                                          flowList,
                                          currentFlowIndex,
                                        },
                                      ],
                                    },
                                    title: '从数据源选择',
                                  },
                                  {
                                    componentName: 'StringSetter',
                                    title: '字符串',
                                  },
                                  {
                                    componentName: 'NumberSetter',
                                    title: '数字',
                                  },
                                  getJSExpressionPrototype({
                                    type: 'formRequest',
                                    prototypeConfig: config,
                                  }),
                                ],
                              },
                            },
                          },
                        ],
                      },
                    },
                  },
                },
              },
              // getJSExpressionPrototype({type:'base'})
            ],
          },
        },
      },
    ];
  },
  action: (config) => {
    const {
      buttonConfig,
      urlParamsDataSource,
      state,
      _context,
      recordDataSource,
    } = config || {};
    const { options } = buttonConfig || {};
    const { dataSourceValues } = options || {};
    if (Array.isArray(dataSourceValues) && dataSourceValues.length > 0) {
      const temp = handleRequestParams(dataSourceValues, {
        urlParamsDataSource,
        recordDataSource: getRealizeValue(recordDataSource) || {},
        state,
      });
      if (isPlainObject(temp) && Object.keys(temp).length > 0) {
        _context?.setState?.(temp);
        emitEvent(CnDataSourceChange);
      }
    }
    return Promise.resolve();
  },
};

const dialog = {
  title: '弹窗',
  value: 'dialog',
  position: ALL_BUTTON_POSITION_LIST,
  action: (config, extra) => {
    const {
      arrayTableConfig,
      buttonConfig,
      _context,
      position,
      componentProps,
      record,
      index,
      selectedRowKeys,
      selectedRowRecords,
      response,
      arrayTableCurrentRow,
    } = config || {};
    let recordDataSource = record;
    if (position === ButtonPosition.arraySubAreaCardOperate) {
      recordDataSource = arrayTableCurrentRow;
    } else if (!record && extra?.field) {
      const { field } = extra;
      const { formItemConfig } = arrayTableConfig || {};
      if (formItemConfig?.name && field) {
        if (field.path.segments.length === 5) {
          const path = field.path.segments.slice(0, 4);
          const tempRow = field?.form?.getValuesIn?.(path);
          if (isPlainObject(tempRow)) {
            recordDataSource = cloneDeep(tempRow);
          }
        } else {
          const list = field?.query?.(formItemConfig?.name)?.value?.();
          if (Array.isArray(list) && list[field?.index]) {
            recordDataSource = cloneDeep(list[field.index]);
          }
        }
      }
    }
    if (position === ButtonPosition.tableCellAfterRequestSuccess) {
      recordDataSource = response?.data || {};
    }

    if (buttonConfig && _context) {
      const { options = {} } = buttonConfig;
      const { _bindDialog, setCurrentRowToDialog } = options;
      if (_bindDialog) {
        const dialogNode = _context.$(_bindDialog);

        let realRecordDataSource = recordDataSource;
        if (setCurrentRowToDialog === false) {
          realRecordDataSource = undefined;
        }
        return new Promise((resolve) => {
          setTimeout(() => {
            const p = dialogNode?.open?.(realRecordDataSource, {
              buttonConfig,
              position,
              selectedRowKeys,
              selectedRowRecords,
            });
            if (typeof p?.then === 'function') {
              p.then((res) => {
                setTimeout(() => {
                  resolve(true);
                }, 8);
              });
            } else {
              setTimeout(() => {
                resolve(true);
              }, 8);
            }
          });
        });
        // table?.load?.();
      }
    }
  },
  getPrototypeList: (position) => {
    const result = [
      getSelectDialogSnippet(),
      // {
      //   name:'openDialogMode',
      //   title:'当一个弹窗复用于新增和编辑多个场景时，你希望本次打开的弹窗用途',
      //   setter:{
      //     componentName:'CnSelectSetter',
      //     props:{
      //       options: getOpenDialogModeEnum({
      //         prefix:'用于'
      //       }),
      //       selectProps:{
      //         hasClear: true,
      //       }
      //     }
      //   }
      // }
    ];
    if (
      [
        ButtonPosition.tableOperate,
        ButtonPosition.arrayTableOperate,
        ButtonPosition.tableCell,
      ].includes(position)
    ) {
      result.splice(1, 0, {
        title: '是否将表格当前行数据默认带入到弹窗表单中',
        name: 'setCurrentRowToDialog',
        setter: {
          componentName: 'RadioGroupSetter',
          props: {
            options: getCommonBoolDataSource(),
          },
        },
        defaultValue: true,
      });
    }
    return result;
  },
};

const cancel = {
  title: '取消（关闭当前弹窗）',
  value: 'cancel',
  position: [
    ButtonPosition.dialog,
    ButtonPosition.formDialog,
    ButtonPosition.form,
  ],
  action: ({ buttonConfig, formData, open, close }) => {
    if (buttonConfig) {
      close && close();
    }
  },
};

const tableReload = {
  title: '刷新表格',
  value: 'tableReload',
  position: ALL_BUTTON_POSITION_LIST,
  getPrototypeList: () => {
    return [...createTableSelectSetters()];
  },
  action: (arg) => {
    const { buttonConfig, _context } = arg || {};
    const { options = {} } = buttonConfig;
    const { _bindTable, keepPagination } = options;
    function reloadOneTable(id) {
      if (typeof id === 'string') {
        const table = _context.$(id);
        if (keepPagination === true) {
          table?.tableLoad()?.();
        } else {
          table?.load?.();
        }
      }
    }

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

/// --------- jsbridge start ---------

const jsBridgeTextSetter = ({ position, config }) => {
  const { urlSetter = 'StringSetter' } =
    getSetterSnippet({
      position,
      optType: 'jsbridge',
      ...config,
    }) || {};
  return urlSetter;
};
const getJsBridgeToastMessageField = ({ initialValue = '' }) => ({
  successToastMessage: {
    title: '成功toast文案',
    setter: {
      componentName: 'StringSetter',
      initialValue,
    },
  },
});
const toastResultCallback = ({ response, inputParams }) => {
  const { successToastMessage } = inputParams || {};
  if (successToastMessage) {
    CnMessage.success?.({ content: successToastMessage });
  }
};

/** api配置 */
const BRIDGE_API_CONFIGS = {
  callPhone: {
    title: '拨打电话',
    props: {
      phoneNumber: {
        title: '电话号码',
        setter: jsBridgeTextSetter,
      },
    },
  },

  scan: {
    title: '扫一扫',
    props: {
      scanType: {
        title: '扫码类型',
        setter: {
          componentName: 'RadioGroupSetter',
          initialValue: 'qrCode',
          props: {
            options: [
              {
                title: '二维码',
                value: 'qrCode',
              },
              {
                title: '条形码',
                value: 'barCode',
              },
            ],
          },
        },
      },
      scanResult: {
        title: '扫码结果',
        setter: {
          componentName: 'RadioGroupSetter',
          initialValue: 'blank',
          props: {
            options: [
              {
                title: '新开窗口',
                value: 'blank',
              },
              {
                title: '复制到剪贴板',
                value: 'copy',
              },
            ],
          },
        },
      },
    },
    /**
     * 端执行回调
     * response: 端执行的结果
     * inputParams: 参数，保存用户做的选择
     */
    resultCallback: ({ response, inputParams }) => {
      const code = response?.code || response?.qrCode || response?.barCode;
      const { scanResult } = inputParams || {};

      if (scanResult === 'blank') {
        CnUniApi?.navigateTo?.({ url: code });
      } else if (scanResult === 'copy') {
        CnUniApi?.setClipboard?.({ text: code })
          ?.then(() => CnMessage.success({ content: '已复制到剪贴板' }))
          ?.catch((err) =>
            CnMessage.error({ content: err?.errMsg || '复制失败' }),
          );
      }
    },
  },
  showSharePanel: {
    title: '分享',
    props: {
      title: {
        title: '分享标题',
        setter: jsBridgeTextSetter,
      },
      content: {
        title: '分享文案',
        setter: jsBridgeTextSetter,
      },
      url: {
        title: '分享网址',
        setter: jsBridgeTextSetter,
      },
      image: {
        title: 'logo主图',
        setter: jsBridgeTextSetter,
      },
    },
  },
  saveImage: {
    title: '保存到相册',
    props: {
      url: {
        title: '图片地址',
        setter: jsBridgeTextSetter,
      },
      ...getJsBridgeToastMessageField({ initialValue: '保存成功' }),
    },
    resultCallback: toastResultCallback,
  },
  setClipboard: {
    title: '复制到剪贴板',
    props: {
      text: {
        title: '复制文案',
        setter: jsBridgeTextSetter,
      },
      ...getJsBridgeToastMessageField({ initialValue: '复制成功' }),
    },
    resultCallback: toastResultCallback,
  },
  choosePhoneContact: {
    title: '通讯录',
    props: {
      needCallPhone: {
        title: '选择后拨打',
        setter: {
          componentName: 'BoolSetter',
          initialValue: true,
        },
      },
    },
    resultCallback: ({ response, inputParams }) => {
      const { needCallPhone } = inputParams || {};
      const mobile = response?.mobile || '';
      const phoneNumber = mobile.split(',')?.[0] || mobile;

      if (needCallPhone) {
        CnUniApi?.callPhone?.({ phoneNumber });
      }
    },
  },
  navigateTo: {
    title: '新开浏览器窗口',
    props: {
      url: {
        title: '新窗口地址',
        setter: jsBridgeTextSetter,
      },
    },
  },
  navigateBack: {
    title: '关闭浏览器窗口',
  },
  setNavigationBarTitle: {
    title: '设置标题',
    props: {
      title: {
        title: '标题名称',
        setter: jsBridgeTextSetter,
      },
    },
  },
  getLocation: {
    title: '获取位置',
  },
  getNetworkType: {
    title: '获取当前网络状态',
  },
  pay: {
    title: '支付',
    props: {
      payStr: {
        title: '订单信息',
        setter: jsBridgeTextSetter,
      },
    },
  },
  vibrate: {
    title: '手机震动',
  },
  snapshot: {
    title: '截屏',
  },
  call: {
    title: '自定义能力',
    props: {
      data: {
        title: '自定义入参',
        setter: {
          componentName: 'ArraySetter',
          props: {
            mode: 'list',
            itemSetter: {
              componentName: 'ObjectSetter',
              initialValue: {
                label: 'param',
              },
              props: {
                config: {
                  items: [
                    {
                      title: '参数名',
                      name: 'label',
                      isRequired: true,
                      description: '参数名',
                      setter: 'StringSetter',
                    },
                    {
                      title: '参数值',
                      name: 'value',
                      isRequired: true,
                      description: '参数值',
                      className: 'cn-param-select-setter',
                      setter: {
                        componentName: 'MixedSetter',
                        props: {
                          setters: [
                            {
                              componentName: 'StringSetter',
                              title: '字符串',
                            },
                            {
                              componentName: 'NumberSetter',
                              title: '数字',
                            },
                            {
                              componentName: 'BoolSetter',
                              title: '布尔（true/false）',
                            },
                          ],
                        },
                      },
                    },
                  ],
                },
              },
            },
          },
        },
      },
    },
  },
};
const jsbridge = {
  title: '跨端JSBridge',
  value: 'jsbridge',
  position: ALL_BUTTON_POSITION_LIST,
  getDefaultProps: () => {
    return {};
  },
  /**
   * 二级面板配置
   * @param position 位置，如：btn_tableOperate
   * @param config TODO: 配置，默认undefined | {__field: Node}
   * @returns
   */
  getPrototypeList: (position, config) => {
    const jsbridgeApis = {
      name: 'apiName',
      title: '跨端能力',
      // setter: https://lowcode-engine.cn/site/docs/guide/appendix/setters
      setter(node) {
        const options = Object.keys(BRIDGE_API_CONFIGS).map((key) => ({
          title: BRIDGE_API_CONFIGS[key]?.title,
          value: key,
        }));

        return {
          componentName: 'SelectSetter',
          initialValue: 'callPhone', // 初始化值
          props: {
            options,
          },
        };
      },
    };

    const apiPropsList = Object.keys(BRIDGE_API_CONFIGS)
      .map((apiName) => {
        const { props = {} } = BRIDGE_API_CONFIGS[apiName];
        return Object.keys(props).map((fieldName) => {
          const fieldConfig = props[fieldName];
          const { title = '', setter = 'StringSetter' } = fieldConfig || {};
          return {
            name: fieldName,
            title,
            condition: (node) => {
              return node?.parent?.getPropValue?.('apiName') === apiName;
            },
            setter:
              typeof setter === 'function'
                ? setter({ position, config })
                : setter,
          };
        });
      })
      .flat();

    return [
      jsbridgeApis, // api选择
      ...apiPropsList, // 配置选择
    ];
  },
  action: async (context) => {
    const {
      buttonConfig: { options } = {},
      // urlParamsDataSource,
      // recordDataSource,
      // state,
      // getExtraParam,
      // position,
      // arrayTableConfig,
      // selectedRowKeys = [],
      // selectedRowRecords = [],
    } = context;
    if (!options) {
      return;
    }

    /**
     * 根据参数表达式，获得真实的值
     * originalParams: 输入参数。用户的原始选择（包含表达式）
     * context: action上下文环境
     */
    const getApiParams = (originalParams, context) => {
      const { urlParamsDataSource, recordDataSource, state, getExtraParam } =
        context;

      const params = Object.keys(originalParams)
        .map((key) => {
          if (key.startsWith('_unsafe_')) {
            return null;
          }

          const originalValue = originalParams[key];
          const newValue = calculateTextExprValue(originalValue, {
            urlParamsDataSource,
            recordDataSource,
            state,
            extraParamList: [],
            getExtraParam,
          });
          return { [key]: newValue };
        })
        .filter((item) => !!item)
        .reduce((prev, current) => {
          return { ...prev, ...current };
        }, {});

      return params;
    };

    /**
     * 根据apiName配置，执行对应的回调函数（如有）
     * apiName： api命名
     * inputParams: 参数，保存用户做的选择
     * response: 端执行的结果
     */
    const excuteApiResultCallback = ({ apiName, inputParams, response }) => {
      const apiNameConfig = Object.keys(BRIDGE_API_CONFIGS)
        .filter((key) => key === apiName)
        .map((key) => BRIDGE_API_CONFIGS[key])?.[0];
      const { resultCallback } = apiNameConfig || {};

      if (!apiNameConfig) {
        return;
      }
      if (!resultCallback) {
        return;
      }

      resultCallback?.({ response, inputParams });
    };

    // cn-uni-api处理
    // 1. 获取真实的参数值
    const { apiName, ...rest } = options;
    const inputParams = getApiParams(rest, context);

    const { log, warn } = console; // TODO: 真机调试不方便，先打点调试，后续删除。
    log('--before jsbridge--:', apiName, inputParams);
    // 2. 执行
    return CnUniApi?.[apiName]?.({ ...inputParams })
      ?.then((response) => {
        // 3. 回调处理
        log('--success jsbridge--:', response);
        excuteApiResultCallback({ apiName, inputParams, response });

        // 处理回调函数，用“动作编排”能力。
        return {
          success: true,
          data: response,
          error: null,
        };
      })
      ?.catch((err) => {
        warn('--fail jsbridge--:', err);
        return {
          success: true,
          data: null,
          error: err,
        };
      });
  },
};

/// --------- jsbridge end ---------

const componentMap = {
  request,
  link,
  submit,
  reset,
  setFormValue,
  tableReload,
  dialog,
  cancel,
  arrayTableAdd,
  arrayTableRemove,
  setDataSourceValue,
  message,
  flowAction,
  jsAction,

  jsbridge,
};

export const createFlowListSetters = (config) => {
  const { position, activeSetter } = config || {};
  return {
    componentName: 'ArraySetter',
    props: {
      mode: 'list',
      itemSetter: {
        componentName: 'ObjectSetter',
        initialValue: {
          active: true,
        },
        props: {
          config: {
            items: [
              {
                name: 'optType',
                display: 'inline',
                title: '动作类型',
                isRequired: true,
                setter: {
                  componentName: 'SelectSetter',
                  props: () => {
                    return {
                      options: getButtonListByPosition(position, {
                        excludeButtonList: ['flowAction'],
                      }),
                    };
                  },
                },
              },
              {
                name: 'active',
                display: 'inline',
                title: '启用',
                isRequired: true,
                setter: activeSetter || {
                  componentName: <CheckboxSetter />,
                  title: '启用/禁用',
                },
              },
              {
                name: 'options',
                // display: 'accordion',
                display: 'plain',
                title: '动作配置项',
                extraProps: {
                  defaultCollapsed: false,
                },
                setter: {
                  componentName: 'ObjectSetter',
                  props: (field) => {
                    const flowList = field?.parent?.parent?.getValue?.();
                    const index = field?.parent?.name;
                    return {
                      config: {
                        items: [
                          ...getButtonPrototypeListByPosition(position, {
                            flowList,
                            currentFlowIndex: index,
                          }),
                        ],
                      },
                    };
                  },
                },
              },
            ],
          },
        },
      },
    },
  };
};

export function getItem(position, componentName, propKey) {
  let result;
  if (componentName) {
    let item = componentMap[componentName];
    if (!item) {
      item = getBizComponent(componentName, position);
    }
    if (item && item.position && item.position.includes(position)) {
      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 getButtonAction(buttonConfig) {
  const { optType, position } = buttonConfig || {};
  if (optType) {
    const action = getItem(position, optType, 'action');
    if (typeof action === 'function') {
      return action;
    }
  }
}

// 获取按钮列表
export function getButtonListByPosition(position, config) {
  const { excludeButtonList = [] } = config || {};
  const defaultList = Object.keys(componentMap);
  const bizComponentNameList = getBizComponentNameList();
  const allComponentList = uniq([...defaultList, ...bizComponentNameList]);
  const result = [];
  if (position !== undefined) {
    allComponentList.forEach((name) => {
      if (excludeButtonList?.includes(name)) {
      } else {
        const component = getItem(position, name);
        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;
}

// 获取按钮prototype列表by position
export function getButtonPrototypeListByPosition(position, config) {
  const defaultList = Object.keys(componentMap);
  let prototypeList = [];
  const bizComponentNameList = getBizComponentNameList();
  const allComponentList = uniq([...defaultList, ...bizComponentNameList]);
  if (position !== undefined) {
    allComponentList.forEach((name) => {
      const item = getItem(position, name) || {};
      const { getPrototypeList, configure = [] } = item;
      if (typeof getPrototypeList === 'function') {
        const temp = getPrototypeList(position, config);
        if (temp && temp.length > 0) {
          prototypeList = [
            ...prototypeList,
            ...handlePrototypeCondition(temp, name, 'optType'),
          ];
        }
      } else if (configure?.length > 0) {
        prototypeList = [
          ...prototypeList,
          ...handlePrototypeCondition(configure, name, 'optType'),
        ];
      }
    });
  }
  return prototypeList;
}

export const createButtonListSetters = (config) => {
  const { position, childrenTitle } = config || {};
  const tempButtonList = getButtonListByPosition(position, config);
  const titleSetter = 'CnI18nSetter';
  const configure = [
    {
      name: 'primaryKey',
      title: '唯一标识',
      condition: {
        type: 'JSFunction',
        value: '() => false',
      },
      initialValue: {
        type: 'JSFunction',
        value:
          'val => {\n                        if (val) return val;\n                        return String(Math.floor(Math.random() * 10000));\n                      }',
      },
      setter: 'StringSetter',
    },
    {
      name: 'children',
      isRequired: true,
      title: childrenTitle || '标题',
      setter: titleSetter,
    },
    {
      name: 'optType',
      title: '按钮功能',
      isRequired: true,
      display: 'inline',
      // extraProps: {
      //   setValue(target, value) {
      //     const currentRowValue = target?.parent?.getValue();
      //     const newButtonInitialValue = getItemDefaultProps(position, value);
      //     target?.parent.setValue({
      //       ...currentRowValue,
      //       optType: value,
      //       options: newButtonInitialValue,
      //     });
      //   },
      // },
      editable: true,
      setter: {
        componentName: 'SelectSetter',
        props: () => {
          return {
            options: getButtonListByPosition(position, config),
          };
        },
      },
    },
  ];
  configure.push({
    name: 'options',
    // display: 'accordion',
    display: 'block',
    title: '按钮配置项',
    extraProps: {
      defaultCollapsed: false,
    },
    setter: {
      componentName: 'ObjectSetter',
      props: () => {
        return {
          config: {
            items: [...getButtonPrototypeListByPosition(position)],
          },
        };
      },
    },
  });

  const styleList = getStyleListByPosition(position);
  if (styleList?.length > 0) {
    configure.push({
      title: '样式',
      type: 'group',
      display: 'accordion',
      collapsed: true,
      items: styleList,
    });
  }
  return {
    componentName: 'ArraySetter',
    props: {
      mode: 'list',
      itemSetter: {
        componentName: 'ObjectSetter',
        initialValue() {
          return {
            primaryKey: uuid(6),
            children: '按钮',
            optType: tempButtonList[0]?.value,
          };
        },
        props: {
          config: {
            items: configure,
          },
        },
      },
    },
  };
};

export function createFormSelectSetters(config) {
  const { mode } = config || {};
  return [
    {
      name: '_bindForm',
      title: '选择表单',
      setter(prop) {
        const options = [];
        prop?.getNode?.()?.document?.nodesMap?.forEach((item) => {
          if (
            item.getPropValue('isCnForm') ||
            item.getPropValue('isCnFormDialog')
          ) {
            let prefix = '表单';
            if (item.getPropValue('isCnFormDialog')) {
              prefix = '弹窗表单';
            }
            const id = item.id || '';
            const title = `${prefix}_${
              handleI18nLabel(item?.propsData?.title) || ''
            }`;
            options.push({
              title,
              value: id,
            });
          }
        });
        return {
          componentName: 'SelectSetter',
          props: {
            mode,
            // hasClear: true,
            options,
          },
        };
      },
    },
  ];
}

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