import _Dropdown from "@alifd/next/es/dropdown";
import _Menu from "@alifd/next/es/menu";
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose";
import _initializerDefineProperty from "@babel/runtime/helpers/initializerDefineProperty";
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
import _applyDecoratedDescriptor from "@babel/runtime/helpers/applyDecoratedDescriptor";
import _initializerWarningHelper from "@babel/runtime/helpers/initializerWarningHelper";
var _excluded = ["className", "field", "setters", "onSetterChange"];
var _dec, _class, _class2, _descriptor, _MixedSetter;
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
import React, { Component } from 'react';
import classNames from 'classnames';
var _AliLowCodeEngine = window.AliLowCodeEngine,
  common = _AliLowCodeEngine.common,
  setters = _AliLowCodeEngine.setters,
  SettingField = _AliLowCodeEngine.SettingField;
import { isSetterConfig, isDynamicSetter } from '@alilc/lowcode-utils';
import { IconConvert } from './icons/convert';
import { intlNode } from './locale';
import { MixedSetterController } from './config';
import './index.less';
import { IconVariable } from './icons/variable';
var editorCabin = common.editorCabin;
var computed = editorCabin.computed,
  obx = editorCabin.obx,
  Title = editorCabin.Title,
  createSetterContent = editorCabin.createSetterContent,
  observer = editorCabin.observer,
  shallowIntl = editorCabin.shallowIntl;
var getSetter = setters.getSetter,
  getSettersMap = setters.getSettersMap;
var dash = '_';
function getMixedSelect(field) {
  var path = field.path || [];
  if (path.length) {
    var key = "_unsafe_MixedSetter" + dash + path[path.length - 1] + dash + "select";
    var newPath = [].concat(path);
    newPath.splice(path.length - 1, 1, key);
    var newKey = field.node.getPropValue(newPath.join('.'));
    if (newKey) return newKey;
    // 兼容下以前的问题情况，如果捕获到，获取 oldUnsafeKey 取值并将其直接置空
    var oldUnsafeKey = "_unsafe_MixedSetter" + dash + path.join(dash) + dash + "select";
    var oldUsedSetter = field.node.getPropValue(oldUnsafeKey);
    if (oldUsedSetter) {
      field.node.setPropValue(newPath.join('.'), oldUsedSetter);
      field.node.setPropValue(oldUnsafeKey, undefined);
    }
    return oldUsedSetter;
  }
  return undefined;
}
function setMixedSelect(field, usedSetter) {
  var path = field.path || [];
  if (path.length) {
    var key = "_unsafe_MixedSetter" + dash + path[path.length - 1] + dash + "select";
    path.splice(path.length - 1, 1, key);
    field.node.setPropValue(path.join('.'), usedSetter);
  }
}
function nomalizeSetters(setters) {
  if (!setters) {
    var normalized = [];
    getSettersMap().forEach(function (setter, name) {
      if (name === 'MixedSetter') {
        return;
      }
      normalized.push({
        name: name,
        title: setter.title || name,
        setter: name,
        condition: setter.condition,
        initialValue: setter.initialValue,
        list: setter.recommend || false,
        valueType: setter.valueType
      });
    });
    return normalized;
  }
  var names = [];
  function generateName(n) {
    var idx = 1;
    var got = n;
    while (names.indexOf(got) > -1) {
      got = n + ":" + idx++;
    }
    names.push(got);
    return got;
  }
  var formattedSetters = setters.map(function (setter) {
    var config = {
      setter: setter,
      list: true
    };
    if (isSetterConfig(setter)) {
      config.setter = setter.componentName;
      config.props = setter.props;
      config.condition = setter.condition;
      config.initialValue = setter.initialValue;
      config.title = setter.title;
      config.valueType = setter.valueType;
    }
    if (typeof config.setter === 'string') {
      config.name = config.setter;
      names.push(config.name);
      var info = getSetter(config.setter);
      if (!config.title) {
        config.title = (info === null || info === void 0 ? void 0 : info.title) || config.setter;
      }
      if (!config.valueType) {
        config.valueType = info === null || info === void 0 ? void 0 : info.valueType;
      }
      if (!config.condition) {
        config.condition = info === null || info === void 0 ? void 0 : info.condition;
      }
      if (!config.initialValue) {
        config.initialValue = info === null || info === void 0 ? void 0 : info.initialValue;
      }
    } else {
      var _config$setter, _config$setter2;
      config.name = generateName(((_config$setter = config.setter) === null || _config$setter === void 0 ? void 0 : _config$setter.displayName) || ((_config$setter2 = config.setter) === null || _config$setter2 === void 0 ? void 0 : _config$setter2.name) || 'CustomSetter');
      if (!config.title) {
        config.title = config.name;
      }
    }
    return config;
  });
  var hasComplexSetter = formattedSetters.filter(function (item) {
    return ['ArraySetter', 'ObjectSetter'].includes(item.setter);
  }).length;
  return formattedSetters.map(function (item) {
    if (item.setter === 'VariableSetter' && hasComplexSetter) {
      item.setter = 'ExpressionSetter';
      item.name = 'ExpressionSetter';
    }
    return item;
  });
}
var MixedSetter = (_dec = obx.ref, observer(_class = (_class2 = (_MixedSetter = /*#__PURE__*/function (_Component) {
  function MixedSetter(props) {
    var _this;
    _this = _Component.call(this, props) || this;
    // TODO: use engine ext.props
    _this.fromMixedSetterSelect = false;
    _this.setters = nomalizeSetters(_this.props.setters);
    _initializerDefineProperty(_this, "used", _descriptor, _this);
    // dirty fix vision variable setter logic
    _this.hasVariableSetter = _this.setters.some(function (item) {
      return item.name === 'VariableSetter';
    });
    _this.useSetter = function (name, usedName) {
      _this.fromMixedSetterSelect = true;
      var field = _this.props.field;
      if (name === 'VariableSetter') {
        var _getSetter;
        var setterComponent = (_getSetter = getSetter('VariableSetter')) === null || _getSetter === void 0 ? void 0 : _getSetter.component;
        if (setterComponent && setterComponent.isPopup) {
          setterComponent.show({
            prop: field
          });
          _this.syncSelectSetter(name);
          return;
        }
      } else {
        // 变量类型直接设undefined会引起初始值变化
        if (name !== _this.used) {
          // reset value
          field.setValue(undefined);
        }
      }
      if (name === _this.used) {
        return;
      }
      var fieldValue;
      var usedSetter = _this.setters.find(function (item) {
        return item.name === usedName;
      });
      // 获取该setter的返回值类型
      // @ts-ignore
      var usedValueType = usedSetter.valueType || ['string'];
      var setter = _this.setters.find(function (item) {
        return item.name === name;
      });

      // @ts-ignore
      var valueType = setter.valueType || ['string'];
      usedValueType.map(function (usedItem) {
        valueType.map(function (item) {
          if (item === usedItem) {
            fieldValue = field.getValue();
          }
          return item;
        });
        return usedItem;
      });
      _this.syncSelectSetter(name);
      if (setter) {
        _this.handleInitial(setter, fieldValue);
      }
    };
    _this.shell = null;
    var _usedSetter = getMixedSelect(_this.props.field);
    if (_usedSetter) {
      _this.used = _usedSetter;
    }
    return _this;
  }
  _inheritsLoose(MixedSetter, _Component);
  var _proto = MixedSetter.prototype;
  _proto.getCurrentSetter = function getCurrentSetter() {
    var field = this.props.field;
    var firstMatched;
    var firstDefault;
    for (var _iterator = _createForOfIteratorHelperLoose(this.setters), _step; !(_step = _iterator()).done;) {
      var setter = _step.value;
      if (setter.name === this.used) {
        return setter;
      }
      if (!setter.condition) {
        if (!firstDefault) {
          firstDefault = setter;
        }
        continue;
      }
      if (!firstMatched && setter.condition(field)) {
        firstMatched = setter;
      }
    }
    return firstMatched || firstDefault || this.setters[0];
  };
  _proto.syncSelectSetter = function syncSelectSetter(name) {
    // TODO: sync into engine ext.props
    var field = this.props.field;
    this.used = name;
    setMixedSelect(field, name);
  };
  _proto.handleInitial = function handleInitial(_ref, fieldValue) {
    var initialValue = _ref.initialValue;
    var _this$props = this.props,
      field = _this$props.field,
      onChange = _this$props.onChange;
    var newValue = initialValue;
    if (newValue && typeof newValue === 'function') {
      newValue = newValue(field);
    } else if (fieldValue) {
      newValue = fieldValue;
    }
    onChange && onChange(newValue);
  };
  _proto.checkIsBlockField = function checkIsBlockField() {
    if (this.shell) {
      var setter = this.shell.firstElementChild;
      if (setter && setter.classList.contains('lc-block-setter')) {
        this.shell.classList.add('lc-block-setter');
      } else {
        this.shell.classList.remove('lc-block-setter');
      }
    }
  };
  _proto.componentDidUpdate = function componentDidUpdate() {
    this.checkIsBlockField();
  };
  _proto.componentDidMount = function componentDidMount() {
    this.checkIsBlockField();
  };
  _proto.renderCurrentSetter = function renderCurrentSetter(currentSetter, extraProps) {
    var _this2 = this;
    var _this$props2 = this.props,
      className = _this$props2.className,
      field = _this$props2.field,
      setters = _this$props2.setters,
      onSetterChange = _this$props2.onSetterChange,
      restProps = _objectWithoutPropertiesLoose(_this$props2, _excluded);
    if (!currentSetter) {
      // TODO: use intl
      if (restProps.value == null) {
        return /*#__PURE__*/React.createElement("span", null, "NullValue");
      } else {
        return /*#__PURE__*/React.createElement("span", null, "InvalidValue");
      }
    }
    var setter = currentSetter.setter,
      props = currentSetter.props;
    var setterProps = {};
    var setterType;
    var dynamicProps = {};
    if (isDynamicSetter(setter)) {
      setterType = setter.call(field, field);
      // { componentName: string; props: object }

      if (typeof setterType === 'object' && typeof setterType.componentName === 'string') {
        dynamicProps = setterType.props || {};
        setterType = setterType.componentName;
      }
    } else {
      setterType = setter;
    }
    if (props) {
      setterProps = props;
      if (typeof setterProps === 'function') {
        setterProps = setterProps(field);
      }
    }
    return createSetterContent(setterType, _extends({
      fromMixedSetterSelect: this.fromMixedSetterSelect
    }, shallowIntl(setterProps), {
      field: field
    }, restProps, extraProps, dynamicProps, {
      onInitial: function onInitial() {
        _this2.handleInitial(currentSetter);
      }
    }));
  };
  _proto.contentsFromPolyfill = function contentsFromPolyfill(setterComponent) {
    var field = this.props.field;
    var n = this.setters.length;
    var setterContent;
    var actions;
    if (n < 3) {
      var _field$getValue;
      var tipContent = field.isUseVariable() ? intlNode('Binded: {expr}', {
        expr: (_field$getValue = field.getValue()) === null || _field$getValue === void 0 ? void 0 : _field$getValue.value
      }) : intlNode('Variable Binding');
      if (n === 1) {
        // =1: 原地展示<当前绑定的值，点击调用 VariableSetter.show>，icon 高亮是否->isUseVaiable，点击 VariableSetter.show
        setterContent = /*#__PURE__*/React.createElement("a", {
          onClick: function onClick() {
            setterComponent.show({
              prop: field
            });
          }
        }, tipContent);
      } else {
        // =2: 另外一个 Setter 原地展示，icon 高亮，点击弹出调用 VariableSetter.show
        // FIXME! use variable placeholder setter

        var otherSetter = this.setters.find(function (item) {
          return item.name !== 'VariableSetter';
        });
        setterContent = this.renderCurrentSetter(otherSetter, {
          value: field.getMockOrValue()
        });
      }
      actions = /*#__PURE__*/React.createElement(Title, {
        className: field.isUseVariable() ? 'variable-binded' : '',
        title: {
          icon: /*#__PURE__*/React.createElement(IconVariable, {
            size: 24
          }),
          tip: tipContent
        },
        onClick: function onClick() {
          setterComponent.show({
            prop: field
          });
        }
      });
    } else {
      // >=3: 原地展示当前 setter<当前绑定的值，点击调用 VariableSetter.show>，icon tip 提示绑定的值，点击展示切换 Setter，点击其它 setter 直接切换，点击 Variable Setter-> VariableSetter.show
      var currentSetter = !this.used && field.isUseVariable() ? this.setters.find(function (item) {
        return item.name === 'VariableSetter';
      }) : this.getCurrentSetter();
      if ((currentSetter === null || currentSetter === void 0 ? void 0 : currentSetter.name) === 'VariableSetter') {
        var _field$getValue$value, _field$getValue2;
        setterContent = /*#__PURE__*/React.createElement("a", {
          onClick: function onClick() {
            setterComponent.show({
              prop: field
            });
          }
        }, intlNode('Binded: {expr}', {
          expr: (_field$getValue$value = (_field$getValue2 = field.getValue()) === null || _field$getValue2 === void 0 ? void 0 : _field$getValue2.value) !== null && _field$getValue$value !== void 0 ? _field$getValue$value : '-'
        }));
      } else {
        setterContent = this.renderCurrentSetter(currentSetter);
      }
      actions = this.renderSwitchAction(currentSetter);
    }
    return {
      setterContent: setterContent,
      actions: actions
    };
  };
  _proto.renderSwitchAction = function renderSwitchAction(currentSetter) {
    var _this3 = this;
    var usedName = (currentSetter === null || currentSetter === void 0 ? void 0 : currentSetter.name) || this.used;
    var triggerNode = /*#__PURE__*/React.createElement(Title, {
      title: {
        tip: intlNode('Switch Setter'),
        // FIXME: got a beautiful icon
        icon: /*#__PURE__*/React.createElement(IconConvert, {
          size: 24
        })
      },
      className: "lc-switch-trigger"
    });
    return /*#__PURE__*/React.createElement(_Dropdown, {
      trigger: triggerNode,
      triggerType: "click",
      align: "tr br"
    }, /*#__PURE__*/React.createElement(_Menu, {
      selectMode: "single",
      hasSelectedIcon: true,
      selectedKeys: usedName,
      onItemClick: function onItemClick(name) {
        return _this3.useSetter(name, usedName);
      }
    }, this.setters.filter(function (setter) {
      return setter.list || setter.name === usedName;
    }).map(function (setter) {
      return /*#__PURE__*/React.createElement(_Menu.Item, {
        key: setter.name
      }, /*#__PURE__*/React.createElement(Title, {
        title: setter.title
      }));
    })));
  };
  _proto.render = function render() {
    var _this4 = this,
      _MixedSetterControlle,
      _MixedSetterControlle2,
      _field$getValue3;
    var _this$props3 = this.props,
      className = _this$props3.className,
      field = _this$props3.field;
    var contents;
    if (this.hasVariableSetter) {
      var _getSetter2;
      // polyfill vision variable setter logic
      var setterComponent = (_getSetter2 = getSetter('VariableSetter')) === null || _getSetter2 === void 0 ? void 0 : _getSetter2.component;
      if (setterComponent && setterComponent.isPopup) {
        contents = this.contentsFromPolyfill(setterComponent);
      }
    }
    if (!contents) {
      var currentSetter = this.getCurrentSetter();
      contents = {
        setterContent: this.renderCurrentSetter(currentSetter),
        actions: this.renderSwitchAction(currentSetter)
      };
    }
    return /*#__PURE__*/React.createElement("div", {
      ref: function ref(shell) {
        _this4.shell = shell;
      },
      className: classNames('lc-setter-mixed', className)
    }, contents.setterContent, /*#__PURE__*/React.createElement("div", {
      className: "lc-setter-actions"
    }, contents.actions), !!MixedSetterController.config.renderSlot && /*#__PURE__*/React.createElement("div", {
      className: "lc-action-slot"
    }, (_MixedSetterControlle = (_MixedSetterControlle2 = MixedSetterController.config).renderSlot) === null || _MixedSetterControlle === void 0 ? void 0 : _MixedSetterControlle.call(_MixedSetterControlle2, {
      field: field,
      bindCode: (_field$getValue3 = field.getValue()) === null || _field$getValue3 === void 0 ? void 0 : _field$getValue3.value
    })));
  };
  return MixedSetter;
}(Component), _MixedSetter.displayName = 'MixedSetter', _MixedSetter), (_descriptor = _applyDecoratedDescriptor(_class2.prototype, "used", [_dec], {
  configurable: true,
  enumerable: true,
  writable: true,
  initializer: null
}), _applyDecoratedDescriptor(_class2.prototype, "getCurrentSetter", [computed], Object.getOwnPropertyDescriptor(_class2.prototype, "getCurrentSetter"), _class2.prototype)), _class2)) || _class);
export default MixedSetter;
MixedSetter.controller = MixedSetterController;