import { define } from './define';
import isNumber from 'lodash/isNumber';
import { sourceOptions } from 'constants/config';
import { deepFind, isRefScreen, urlCacheReplace } from './utils';
import { arrayExpand } from './data-helper';
import { getId } from './interaction';
import isObject from 'lodash/isObject';
import { api } from 'constants/config';
import { DataFrom } from 'models/component.types';

import { Utils } from '@easyv/react-gui';
const isRelativeUrl = (_cover) => {
  return _cover && !/http[s]{0,1}:\/\/([\w.]+\/?)\S*/.test(_cover);
};

const {
  getComponentDimension,
  updateArrayConfig,
  transformConfig,
  mergeStyleConfig,
  updateArrayWithObject,
} = Utils;

export const reserveCallbackKeys = ['mm', 'ss'];

export function getComponent(moduleName, version, tenantId?: number) {
  const m = moduleName + '@' + version;
  const component = window.component && window.component[m];
  if (component) {
    return Promise.resolve(component);
  } else {
    return new Promise((resolve) => {
      define(
        m + new Date().getTime() + Math.random(),
        [m],
        (com) => {
          !window.component && (window.component = {});
          window.component[m] = com;
          resolve(com);
        },
        tenantId,
      );
    });
  }
}

export function getAssetsEventComponentConfig(config: { [x: string]: any }) {
  // 筛选自定义事件 -> 更新组件配置（涉及资源相关）
  if (isObject(config)) {
    const assetTypes = /data\/\S+\.\S+/;
    return Object.values(config).reduce((all, curr) => {
      if (isObject(curr)) {
        return all.concat(getAssetsEventComponentConfig(curr));
      } else if (typeof curr === 'string' && assetTypes.test(curr)) {
        return all.concat(curr);
      }
      return all;
    }, []);
  }
  return [];
}

export function getAssetsFromConfig(config) {
  const assetTypes = [
    'uploadImage',
    'selectCard',
    'image',
    'video',
    'model',
    'audio',
    'folder',
    'uploadModel',
  ];
  config = transformConfig(config);

  const _getAssetsFromConfig = (config, assets = []) => {
    return config.reduce(
      (all, item) =>
        assetTypes.includes(item.type) && item.value
          ? item.type === 'folder'
            ? all.concat(
                typeof item.value === 'object'
                  ? item.value.options
                  : JSON.parse(item.value).options,
              )
            : item.type === 'selectCard'
            ? all.concat(
                item.config.options.filter((d) => isRelativeUrl(d.cover)).map((d) => d.cover),
              )
            : all.concat(item.value)
          : Array.isArray(item.value)
          ? _getAssetsFromConfig(item.value, all)
          : all,
      assets,
    );
  };

  return _getAssetsFromConfig(config);
}

export function getGroupDimension(dimensions) {
  if (dimensions && dimensions.length) {
    const minLeft = Math.min(...dimensions.map((d) => d.left));
    const minTop = Math.min(...dimensions.map((d) => d.top));
    const maxRight = Math.max(...dimensions.map((d) => d.left + d.width));
    const maxBottom = Math.max(...dimensions.map((d) => d.top + d.height));
    const groupWidth = maxRight - minLeft;
    const groupHeight = maxBottom - minTop;

    return { left: minLeft, top: minTop, width: groupWidth, height: groupHeight };
  } else {
    return { left: 0, top: 0, width: 0, height: 0 };
  }
}

export function isInGroup(id, groups, layers) {
  const groupPath = getGroupPath(id, layers);
  return groupPath.some((d) => groups.indexOf(d) > -1);
}

export function getGroupPath(id, layers) {
  let path = [];
  function _find(val, arr, position) {
    arr.some((item) => {
      if (item.id === val) {
        path = position;
        return true;
      } else if (item.components) {
        return _find(val, item.components, position.concat(item.id));
      }
    });
  }
  _find(id, layers, path);
  return path;
}

export function flattenToObject(layers, path = [], groupPath = []) {
  return layers.reduce((all, item, index) => {
    if (item.components) {
      return {
        ...all,
        [item.id]: {
          ...item,
          path: path.concat(index),
          groupPath,
        },
        ...flattenToObject(item.components, path.concat(index), groupPath.concat(item.id)),
      };
    } else {
      return {
        ...all,
        [item.id]: {
          ...item,
          path: path.concat(index),
          groupPath,
        },
      };
    }
  }, {});
}

export function arrayToObject(components) {
  const componentsById = {};

  components.forEach((component) => {
    componentsById[component.id] = component;
  });

  return componentsById;
}

export function getGroupChildren(group) {
  return group && group.components
    ? group.components.reduce(
        (all, item) => (item.components ? all.concat(getGroupChildren(item)) : all.concat(item)),
        [],
      )
    : [];
}

export function filterSelectedLayers(selected, layers) {
  return layers.reduce((all, item) => {
    if (selected.indexOf(item.id) > -1) {
      return all.concat({ id: item.id });
    } else if (item.components) {
      const children = filterSelectedLayers(selected, item.components);
      if (children.length) {
        return all.concat({ id: item.id, components: children });
      } else {
        return all;
      }
    } else {
      return all;
    }
  }, []);
}

export function replaceCallbacks({ query, callbackValues, quote }) {
  return query.replace(/:([a-zA-Z]\w*)/g, (_match, p1) => {
    let value = callbackValues[p1];

    if (typeof value === 'object') {
      value = JSON.stringify(value);
    }

    if (typeof value === 'string') {
      if (quote === 'single') {
        value = `'${value}'`;
      } else if (quote === 'double') {
        value = `"${value}"`;
      }
    }

    return value;
  });
}

export function replaceExecs(str) {
  return str.replace(/\$\{([\w\W]+?)\}\$/g, (_match, p1) => {
    return eval(p1);
  });
}

export function updateObjectKey(data, code) {
  const o = {};
  if (typeof data === 'object' && Object.values(data).length) {
    for (const k in data) {
      o[`${code}_${k}`] = data[k];
    }
  }
  return o;
}

export function getDataContainerCallbackKeys(dataContainers, filters) {
  const callbackKeys = {
    filter: updateObjectKey(getFilterCallbackKeys(dataContainers, filters), 'containers'),
    data: updateObjectKey(getCallbackKeys(dataContainers), 'containers'),
  };
  return callbackKeys;
}

export function getAllCallbackKeys(components, filters) {
  const callbackKeys = {
    filter: getFilterCallbackKeys(components, filters),
    data: getCallbackKeys(components),
    interaction: getInteractionCallbackKeys(components),
  };

  return callbackKeys;
}

export function getInteractionCallbackKeys(components) {
  const callbackKeys = {};

  /**
   * @description: config:{ callback:true }
   * @param {*} interaction
   * @return {string[]}
   */
  function getConfigCallbackKeys(interaction) {
    // config 来标识callback
    if (Array.isArray(interaction?.value)) {
      return interaction.value.reduce((all, curr) => {
        if (curr.config.callback && curr.value && typeof curr.value === 'string') {
          all = all.concat(curr.value);
        }
        return all.concat(getConfigCallbackKeys(curr.value));
      }, []);
    }
    return [];
  }

  /**
   * @description: {name = 'callback'}
   * @param {*} interaction
   * @return {string[]}
   */
  function getNameCallbackKeys(callbacks) {
    // name为callback的回调字段
    const keys =
      (Array.isArray(callbacks?.value) &&
        callbacks.value
          .reduce((all, callback) => {
            if (Array.isArray(callback?.value)) {
              const configCallbacks = callback.value?.filter((d) => d.config?.callback);
              const result =
                configCallbacks?.length > 0
                  ? configCallbacks.map((o) => o.value)
                  : callback.value?.[1]?.value;
              return all.concat(result);
            }
            return all;
          }, [])
          .filter((d) => d)) ||
      [];

    return keys;
  }

  components.forEach((component) => {
    // eslint-disable-next-line prefer-const
    let { id, config } = component;
    config = transformConfig(config);

    const interaction = config.find((d) => d.name === 'interaction');
    const nameCallbacksConfig = interaction?.value?.find((d) => d.name === 'callback');
    const otherCallbacksConfig = interaction?.value?.filter((d) => d.name !== 'callback');

    const nameCallbacks = getNameCallbackKeys(nameCallbacksConfig);
    const configCallbacks = getConfigCallbackKeys(otherCallbacksConfig);
    const keys = Array.from(new Set(nameCallbacks.concat(configCallbacks).filter((d) => d)));

    // 除去events交互事件/remoteControl
    const otherConfig =
      interaction &&
      interaction.value.filter(
        (d) => d.name !== 'events' || d.name !== 'remoteControl' || d.name !== 'callback',
      );

    // 通过_callback来标识是否为回调字段
    const otherKeys = deepFind(
      otherConfig,
      (item) => item.config && item.config.callback === true,
      'value',
    )
      .map((d) => d.value)
      .filter((d) => d);
    const allKeys = Array.from(new Set(keys.concat(otherKeys)));
    if (allKeys.length) {
      callbackKeys[id] = allKeys;
    }
  });

  return callbackKeys;
}

export function getFilterCallbackKeys(components, filters) {
  const callbackKeys = {};

  components.forEach((component) => {
    const { id, filters: componentFilters } = component;

    if (Array.isArray(componentFilters)) {
      const usedFilters = componentFilters.filter((d) => d.enable);
      const keys = usedFilters
        .map((d) => filters.find((v) => v.id === d.id))
        .reduce((all, item) => {
          if (item && item.callbackKeys && item.callbackKeys.length) {
            return all.concat(item.callbackKeys);
          } else {
            return all;
          }
        }, []);

      if (keys.length) {
        callbackKeys[id] = Array.from(new Set(keys));
      }
    }
  });

  return callbackKeys;
}

export function getCallbackKeys(components) {
  const callbackKeys = {};

  components.forEach((component) => {
    const { id, dataType, dataConfigs } = component;

    const dataConfig = dataConfigs[dataType];
    if (dataConfig) {
      const keys: any[] = [];
      const callbackReg = /:([a-zA-Z]\w*)/g;

      if (
        dataType === 'mysql' ||
        dataType === 'mssql' ||
        dataType === 'oracle' ||
        dataType === 'postgresql' ||
        dataType === 'clickhouse' ||
        dataType === 'damengdb' || 
        dataType === 'db2'
      ) {
        const { config = {}, callbackKeys = [] } = dataConfig;
        const { sql } = config;
        if (callbackKeys.length) {
          keys.push(...callbackKeys);
        }
        if (callbackReg.test(sql)) {
          sql.replace(callbackReg, (_match, p) => {
            if (!reserveCallbackKeys.includes(p)) {
              keys.push(p);
            }
          });
        }
      } else if (dataType === 'api' || dataType === 'apiGateway' || dataType === 'dtInsight') {
        const { config = {} } = dataConfig;
        const { body, params, path, headers } = config;
        if (callbackReg.test(body)) {
          body.replace(callbackReg, (_match, p) => {
            keys.push(p);
          });
        }

        if (callbackReg.test(params)) {
          params.replace(callbackReg, (_match, p) => {
            keys.push(p);
          });
        }

        if (callbackReg.test(path)) {
          path.replace(callbackReg, (_match, p) => {
            keys.push(p);
          });
        }

        if (callbackReg.test(headers)) {
          headers.replace(callbackReg, (_match, p) => {
            keys.push(p);
          });
        }
      }
      if (keys.length) {
        callbackKeys[id] = Array.from(new Set(keys));
      }
    }
  });

  return callbackKeys;
}

export function replaceCallbacksAndExecs({ query, needQuote, callbackValues }) {
  if (!query) {
    return query;
  }

  const execReg = /\$\{([\w\W]+?)\}\$/g;
  const callbackReg = /:([a-zA-Z]\w*)/g;
  let result = query;

  if (execReg.test(result)) {
    result = result.replace(execReg, (_match, p) => {
      return eval(p);
    });
  }

  if (callbackReg.test(result)) {
    result = result.replace(callbackReg, (_match, p) => {
      let value = callbackValues[p];
      if (needQuote) {
        if (typeof value === 'object') {
          value = `'${JSON.stringify(value)}'`;
        } else if (typeof value === 'string') {
          value = `'${value}'`;
        }
      } else {
        if (typeof value === 'object') {
          value = JSON.stringify(value);
        }
      }
      return value;
    });
  }

  return result;
}

export const getCallbackValuesFromQuery = ({ query, callbackValues }) => {
  let needReplacedCallbackValues = {};
  if (!query) {
    return needReplacedCallbackValues;
  }

  const callbackReg = /:([a-zA-Z]\w*)/g;
  let result = query;

  if (callbackReg.test(result)) {
    query.replace(callbackReg, (_match, p) => {
      let value = callbackValues[p];
      needReplacedCallbackValues[p] =
        typeof value === 'object' ? JSON.parse(JSON.stringify(value) || 'null') : value;
    });
  }

  return needReplacedCallbackValues;
};

export function getCenterFromDimension(dimension) {
  try {
    const left = Math.min(...dimension.map((d) => d.left));
    const right = Math.max(...dimension.map((d) => d.left + d.width));
    const top = Math.min(...dimension.map((d) => d.top));
    const bottom = Math.max(...dimension.map((d) => d.top + d.height));

    return [Math.round((left + right) / 2), Math.round((top + bottom) / 2)];
  } catch (error) {
    console.error(error);
    return [0, 0];
  }
}

export function getDimensionFromChildren(dimensions) {
  try {
    const left = Math.min(...dimensions.map((d) => d.left));
    const right = Math.max(...dimensions.map((d) => d.left + d.width));
    const top = Math.min(...dimensions.map((d) => d.top));
    const bottom = Math.max(...dimensions.map((d) => d.top + d.height));

    return {
      left,
      top,
      width: Math.round(right - left),
      height: Math.round(bottom - top),
      center: [Math.round((left + right) / 2), Math.round((top + bottom) / 2)],
    };
  } catch (error) {
    console.error(error);
    return {
      left: 0,
      top: 0,
      width: 0,
      height: 0,
      center: [0, 0],
    };
  }
}

export function transformDataConfigToServer(dataConfigs) {
  return Object.keys(dataConfigs)
    .filter((d) => d !== 'static')
    .reduce((all, item) => {
      const dataConfig = dataConfigs[item];
      all[item] = {
        data: dataConfig.config,
        fields: dataConfig.fields,
      };
      return all;
    }, {});
}

export function transformComponentToServer(component) {
  if (component) {
    const {
      id,
      name,
      base,
      from,
      config,
      dataConfigs,
      dataFrom,
      dataType,
      parent,
      useFilter,
      filters,
      autoUpdate,
      dataContainers,
      events,
      triggers,
      actions,
    } = component;

    return {
      id,
      name,
      base,
      config,
      dataFrom,
      dataContainers,
      dataConfig: transformDataConfigToServer(dataConfigs),
      dataType: dataType,
      parent: parent,
      useFilter: useFilter,
      filters: filters,
      autoUpdate: autoUpdate,
      staticData: dataConfigs.static,
      events,
      from,
      triggers,
      actions,
    };
  }
}

export function transformComponents(components, screenId) {
  const childrenIdByParentId = {};

  components = components.map((d) => {
    if (d.parent) {
      if (childrenIdByParentId[d.parent]) {
        childrenIdByParentId[d.parent].push(d.id);
      } else {
        childrenIdByParentId[d.parent] = [d.id];
      }
    }
    return componentOperator.createFromServer({ ...d, screenId });
  });

  return components.map((d) =>
    childrenIdByParentId[d.id] ? { ...d, children: childrenIdByParentId[d.id] } : d,
  );
}

export function getThemeComponent(component: any = {}, themes: any = []) {
  const { base } = component;
  const componentDefaultTheme = themes.find(
    (d: any) => d.moduleName === base.module_name && d.isDefault,
  );
  return componentDefaultTheme
    ? {
        ...component,
        config: mergeStyleConfig(component.config, componentDefaultTheme.config),
      }
    : component;
}

export const componentOperator = {
  /**
   * 创建本地对象模型
   */
  create({
    id,
    uniqueTag,
    name,
    base,
    config,
    dataConfigs,
    dataType,
    parent,
    autoUpdate,
    filters,
    useFilter,
    children,
    screenId,
    events = [],
    triggers = [],
    actions = [],
    from,
  }) {
    return {
      id,
      uniqueTag,
      name: name || base.name,
      base,
      config,
      dataConfigs: dataConfigs || {},
      dataType: dataType || 'static',
      parent,
      autoUpdate: autoUpdate || { isAuto: false, interval: 60 },
      filters: filters || [],
      useFilter: useFilter || false,
      children: children,
      screenId,
      events,
      triggers,
      actions,
      from,
    };
  },
  /**
   * 转化server属性到本地
   */
  createFromServer({
    id,
    uniqueTag,
    name,
    config = [],
    base = {},
    dataType,
    dataConfig,
    autoUpdate = {},
    useFilter,
    filters = [],
    staticData = {},
    baseURL,
    parent,
    children,
    screenId,
    events = [],
    triggers = [],
    actions = [],
    from,
    dataContainers,
    dataFrom = DataFrom.DEFAULT,
  }) {
    return {
      id,
      uniqueTag,
      name,
      config,
      base,
      dataFrom,
      dataType,
      dataConfigs: componentOperator.createDataConfigsFromServer(staticData, dataConfig, dataType),
      autoUpdate,
      useFilter,
      filters,
      parent,
      children,
      baseURL,
      screenId,
      events,
      triggers,
      actions,
      from,
      dataContainers,
    };
  },

  createDataConfigsFromServer(staticDataConfig, dataConfig, dataType) {
    let configs = {
      static: staticDataConfig,
    };

    if (dataConfig) {
      const { type, callbackKeys = [], ...sources } = dataConfig;
      const sourcesValue = sourceOptions.map((d) => d.value);

      Object.keys(sources).forEach((d) => {
        if (sourcesValue.includes(d)) {
          configs[d] = {
            data: [],
            fields: sources[d].fields || staticDataConfig.fields,
            config: sources[d].data,
            callbackKeys: callbackKeys,
          };
        }
      });
    }

    if (!configs[dataType]) {
      const callbackKeys = ['mysql', 'mssql', 'oracle', 'postgresql', 'clickhouse'].includes(
        dataType,
      )
        ? dataConfig
          ? dataConfig.callbackKeys
          : undefined
        : undefined;

      configs = {
        ...configs,
        [dataType]: {
          fields: staticDataConfig.fields,
          data: [],
          callbackKeys,
        },
      };
    }

    return configs;
  },
  /**
   * 获取子组件列表
   */
  getChildren(parentId, table) {
    return Object.keys(table)
      .filter((key) => table[key].parent === parentId)
      .map((key) => table[key]);
  },
  /**
   * 更新组件配置的位置
   */
  moveTo({ x, y, configs }) {
    let newConfig = configs;
    if (isNumber(x)) {
      newConfig = updateArrayConfig(newConfig, {
        path: ['chart', 'dimension', 'chartPosition', 'left'],
        value: x,
      });
    }
    if (isNumber(y)) {
      newConfig = updateArrayConfig(newConfig, {
        path: ['chart', 'dimension', 'chartPosition', 'top'],
        value: y,
      });
    }
    return newConfig;
  },
  /**
   * 更新组件配置的尺寸
   */
  scaleTo({ width, height, configs }) {
    let newConfig = configs;
    if (isNumber(width)) {
      newConfig = updateArrayConfig(newConfig, {
        path: ['chart', 'dimension', 'chartDimension', 'width'],
        value: width,
      });
    }
    if (isNumber(height)) {
      newConfig = updateArrayConfig(newConfig, {
        path: ['chart', 'dimension', 'chartDimension', 'height'],
        value: height,
      });
    }

    return newConfig;
  },
  isComponent(id) {
    return !isNaN(+id);
  },
  isPanel(id) {
    return (id + '').startsWith('panel_');
  },
  isGroup(id) {
    return (id + '').startsWith('group_');
  },
  getLayerScale({ layer, componentsById, panelsById }) {
    const getScale = (layer) => {
      if (componentOperator.isComponent(layer.id)) {
        const component = componentsById[layer.id];
        if (component) {
          const scale = getComponentDimension(component.config);
          return { ...scale, id: layer.id };
        } else {
          return {};
        }
      }
      if (componentOperator.isPanel(layer.id) || isRefScreen(layer.id)) {
        const panelId: any = getId(layer.id);
        const panel = panelsById[panelId];
        if (panel) {
          const { left, top, width, height } = panel.config;
          return { id: layer.id, left, top, width, height };
        } else {
          return {};
        }
      }
      if (componentOperator.isGroup(layer.id)) {
        let list: any = [];
        arrayExpand(
          layer.components,
          function arrayExpandLoopCheck(item) {
            return item.components;
          },
          function arrayExpandLoop(item) {
            if (!componentOperator.isGroup(item.id)) {
              list.push(item);
            }
          },
        );
        list = list.map(getScale).filter(Boolean);
        return { ...getGroupDimension(list), id: layer.id };
      }
    };
    return getScale(layer);
  },
};

// 不知道放哪 暂时放这
export function batchModifComponentConfig(componentsById, updates, components) {
  return components
    .map((id) => {
      const component = componentsById[id];
      if (component) {
        return {
          componentId: id,
          updateData: { config: updateArrayConfig(component.config, updates) },
        };
      }
    })
    .filter((v) => v);
}

export function mergeFields(newFields: any = [], oldFields: any = []) {
  if (!newFields || !oldFields) {
    return newFields;
  }

  return newFields.map((d) => {
    const prevValue = oldFields.find((o) => o.name === d.name);
    if (prevValue) {
      return {
        ...d,
        value: prevValue.value,
      };
    } else {
      return d;
    }
  });
}

export function getModalEditConfig(config) {
  const padding = 36;
  const configWidth = 330;
  const dimension = getComponentDimension(config);
  const windowWidth = document.body.clientWidth;
  const windowHeight = document.body.clientHeight;
  const boxDom = document.getElementById('j-previewarea');
  const simulatorContainerDom = document.getElementById('m-simulator-container');
  const simulatorDom = document.getElementById('m-simulator');
  if (!simulatorContainerDom || !simulatorDom || !boxDom) {
    return config;
  }

  const scale = simulatorContainerDom.clientWidth / simulatorDom.clientWidth;
  const boxRect = boxDom.getBoundingClientRect();
  const simulatorContainerRect = simulatorContainerDom.getBoundingClientRect();
  const editContainerWidth = windowWidth - padding * 2 - configWidth;
  const editContainerHeight = windowHeight - padding * 2;
  const zoomX = editContainerWidth / (dimension.width * scale);
  const zoomY = editContainerHeight / (dimension.height * scale);
  const componentScale = Math.min(zoomX, zoomY);
  const positionX =
    Math.floor((editContainerWidth - dimension.width * scale * componentScale) / 2) + padding;
  const positionY =
    Math.floor((editContainerHeight - dimension.height * scale * componentScale) / 2) + padding;
  const componentX = Math.floor((positionX - (simulatorContainerRect.x - boxRect.x)) / scale);
  const componentY = Math.floor((positionY - (simulatorContainerRect.y - boxRect.y)) / scale);
  const componentWidth = Math.floor(dimension.width * componentScale);
  const componentHeight = Math.floor(dimension.height * componentScale);

  return updateArrayWithObject(config, {
    chart: {
      dimension: {
        chartPosition: { left: componentX, top: componentY },
        chartDimension: { width: componentWidth, height: componentHeight },
      },
    },
  });
}

export { getComponentDimension };

/** * * @returns 根据当前路由获取请求组件数据的接口 */
export const getComponentDataApiByPathName = () => {
  const pathname = window.location.pathname;
  if (
    /\/sharedPortal\//i.test(pathname) ||
    /\/sharescreen\//i.test(pathname) ||
    /\/app\/detail\//i.test(pathname)
  ) {
    return urlCacheReplace(api.sharedComponentDataGet); //门户发布页、大屏发布页、终端远程控制页都走sharedComponentDataGet
  }

  if (/\/insert\/screen\//i.test(pathname)) {
    return api.appComponentGet; //终端获取
  }
  return api.componentDataGet;
};

// 根据http请求报文替换回调参数为真实的值
const replaceCallbackParam = ({ query, callbackValues }) => {
  const needReplaceReg = /:([a-zA-Z]\w*)|(\$\{([\w\W]+?)\}\$)/;
  if (needReplaceReg.test(query)) {
    const replacedQuery = replaceCallbacksAndExecs({ query, callbackValues, needQuote: false });
    return /undefined/.test(replacedQuery) ? query : replacedQuery;
  }
  return query;
};

/**
 * ["api","apiGateway","dtInsight"].includes(dataType) === true
 * @param param0
 * @returns API 接口请求时，替换回调参数为真实的值
 */
export const getReplacedCallbackApiQuery: ({ callbackValues, config }) => {
  params: any;
  path: any;
  headers: any;
  body?: any;
  needCookie?: boolean;
} = ({ callbackValues, config }) => {
  const { body, params, path = '', headers, method, reqFromBack, needCookie } = config;
  const replacedParams = replaceCallbackParam({ query: params, callbackValues });
  const replacedPath = replaceCallbackParam({ query: path, callbackValues });
  const replacedHeaders = replaceCallbackParam({ query: headers, callbackValues });
  const replacedBody = replaceCallbackParam({ query: body, callbackValues });

  return Object.assign(
    Object.assign(
      {
        params: replacedParams,
        path: replacedPath,
        headers: replacedHeaders,
      },
      reqFromBack ? {} : { needCookie },
    ),
    ['post', 'put', 'patch'].includes(method) ? { body: replacedBody } : {},
  );
};

export const getReplacedCallbackSqlQuery = ({ config, id, callback }) => {
  const { callbackValues, callbackKeys: renameCallbackKeys } = callback;
  const { data: callbackDataKeys = {} } = renameCallbackKeys || {};
  const { sql } = config;
  let callbackKeys: any = [];
  // sql存在，表明是编辑或者预览页，这个时候需要前端监测是否有回调
  if (sql) {
    if (/:([a-zA-Z]\w*)/.test(sql)) {
      sql.replace(/:([a-zA-Z]\w*)/g, (_match, p) => {
        if (!reserveCallbackKeys.includes(p)) {
          callbackKeys.push(p);
        }
      });
    }
  } else {
    // 不存在时，表明是分享页 或者 sql为空，统一作为分享页来处理
    callbackKeys = callbackDataKeys[id] || [];
  }

  if (callbackKeys.length) {
    const sqlCallbackValues = Array.from(new Set(callbackKeys)).reduce((all: any, item: any) => {
      all[item] = (callbackValues as any)[item];
      return all;
    }, {});

    return {
      callbackValues: sqlCallbackValues,
    };
  }
  return {};
};

export const getCurComponentCallbackValues = (id, callback, type: 'component' | 'containers') => {
  const { callbackKeys = {}, callbackValues = {} } = callback || {};
  const { data: callbackData = {} } = callbackKeys;
  const curComponentCallbackKeys =
    (type === 'component' ? callbackData[id] : callbackData[`containers_${id}`]) || [];
  const usedCallbackValues = curComponentCallbackKeys.reduce(
    (pre, cur) => ({ ...pre, [cur]: callbackValues[cur] }),
    {},
  );
  return usedCallbackValues;
};
