import _extends from "@babel/runtime/helpers/extends";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
import React, { Component } from "react";
import { Utils } from "@react-awesome-query-builder/core";
import PropTypes from "prop-types";
import range from "lodash/range";
import { getOpCardinality } from "../../utils/stuff";
import { useOnPropsChanged } from "../../utils/reactUtils";
import pick from "lodash/pick";
import WidgetFactory from "./WidgetFactory";
import classNames from "classnames";
import { Col, getWidgetId, getRenderFromConfig } from "../utils";
var _Utils$ConfigUtils = Utils.ConfigUtils,
  getFieldConfig = _Utils$ConfigUtils.getFieldConfig,
  getOperatorConfig = _Utils$ConfigUtils.getOperatorConfig,
  getFieldWidgetConfig = _Utils$ConfigUtils.getFieldWidgetConfig,
  getWidgetForFieldOp = _Utils$ConfigUtils.getWidgetForFieldOp,
  getValueSourcesForFieldOp = _Utils$ConfigUtils.getValueSourcesForFieldOp;
var getValueLabel = Utils.RuleUtils.getValueLabel;
var createListWithOneElement = Utils.DefaultUtils.createListWithOneElement;
var shallowEqual = Utils.OtherUtils.shallowEqual;
var isImmutable = Utils.TreeUtils.isImmutable;
var funcArgDummyOpDef = {
  cardinality: 1
};
var Widget = /*#__PURE__*/function (_Component) {
  function Widget(_props) {
    var _this;
    _classCallCheck(this, Widget);
    _this = _callSuper(this, Widget, [_props]);
    _this._setValue = function (isSpecialRange, delta, widgetType, widgetId,
    // bound!
    value, asyncListValues) {
      var _meta = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
      if (!_meta.widgetId) {
        _meta.widgetId = widgetId;
      }
      if (isSpecialRange && Array.isArray(value)) {
        var oldRange = [_this.props.value.get(0), _this.props.value.get(1)];
        if (oldRange[0] != value[0]) _this.props.setValue(0, value[0], widgetType, asyncListValues, _meta);
        if (oldRange[1] != value[1]) _this.props.setValue(1, value[1], widgetType, asyncListValues, _meta);
      } else {
        _this.props.setValue(delta, value, widgetType, asyncListValues, _meta);
      }
    };
    _this._setValueSrc = function (delta, widgetId,
    // bound!
    srcKey) {
      var _meta = {
        widgetId: widgetId
      };
      _this.props.setValueSrc(delta, srcKey, _meta);
    };
    _this.renderWidget = function (delta, meta, props) {
      var config = props.config,
        isFuncArg = props.isFuncArg,
        leftField = props.leftField,
        operator = props.operator,
        values = props.value,
        valueError = props.valueError,
        fieldError = props.fieldError,
        readonly = props.readonly,
        parentField = props.parentField,
        parentFuncs = props.parentFuncs,
        id = props.id,
        groupId = props.groupId,
        fieldSrc = props.fieldSrc,
        fieldType = props.fieldType,
        isLHS = props.isLHS,
        setFuncValue = props.setFuncValue;
      var settings = config.settings;
      var widgets = meta.widgets,
        iValues = meta.iValues,
        aField = meta.aField,
        valueSources = meta.valueSources;
      var value = isFuncArg ? iValues : values;
      var field = isFuncArg ? leftField : aField;
      var _widgets$delta = widgets[delta],
        valueSrc = _widgets$delta.valueSrc,
        valueLabel = _widgets$delta.valueLabel,
        widgetId = _widgets$delta.widgetId;
      var hasValueSources = valueSources.length > 1 && !readonly;
      var widgetLabel = settings.showLabels ? /*#__PURE__*/React.createElement("label", {
        key: "label-" + widgetId,
        className: "rule--label"
      }, valueLabel.label) : null;
      return /*#__PURE__*/React.createElement("div", {
        key: "wrapper-" + widgetId,
        className: classNames(valueSrc === "func" ? "widget--func" : "widget--widget", hasValueSources ? "widget--has-valuesrcs" : "widget--has-no-valuesrcs")
      }, valueSrc === "func" ? null : widgetLabel, /*#__PURE__*/React.createElement(WidgetFactory, _extends({
        key: widgetId,
        id: id // id of rule
        ,
        groupId: groupId,
        widgetId: widgetId,
        valueSrc: valueSrc,
        delta: delta,
        value: value,
        valueError: valueError,
        fieldError: fieldError,
        isFuncArg: isFuncArg,
        isLHS: isLHS
      }, pick(meta, ["isSpecialRange", "fieldDefinition", "asyncListValues"]), pick(widgets[delta], ["widget", "widgetDefinition", "widgetValueLabel", "valueLabels", "textSeparators", "setValue"]), {
        setFuncValue: setFuncValue,
        config: config,
        field: field,
        fieldSrc: fieldSrc,
        fieldType: fieldType,
        parentField: parentField,
        parentFuncs: parentFuncs,
        operator: operator,
        readonly: readonly
      })));
    };
    _this.renderValueSources = function (delta, meta, props) {
      var config = props.config,
        isFuncArg = props.isFuncArg,
        leftField = props.leftField,
        operator = props.operator,
        readonly = props.readonly;
      var settings = config.settings;
      var valueSources = meta.valueSources,
        widgets = meta.widgets,
        aField = meta.aField,
        valueSourcesOptions = meta.valueSourcesOptions;
      var field = isFuncArg ? leftField : aField;
      var _widgets$delta2 = widgets[delta],
        valueSrc = _widgets$delta2.valueSrc,
        setValueSrc = _widgets$delta2.setValueSrc;
      var ValueSources = _this.ValueSources;
      var sourceLabel = settings.showLabels ? /*#__PURE__*/React.createElement("label", {
        className: "rule--label"
      }, "\xA0") : null;
      return valueSources.length > 1 && !readonly && /*#__PURE__*/React.createElement("div", {
        key: "wrapper-" + "valuesrc-" + delta,
        className: "widget--valuesrc"
      }, sourceLabel, /*#__PURE__*/React.createElement(ValueSources, {
        key: "valuesrc-" + delta,
        delta: delta,
        valueSources: valueSourcesOptions,
        valueSrc: valueSrc,
        config: config,
        field: field,
        operator: operator,
        setValueSrc: setValueSrc,
        readonly: readonly,
        title: settings.valueSourcesPopupTitle
      }));
    };
    _this.renderSep = function (delta, meta, props) {
      var config = props.config;
      var widgets = meta.widgets;
      var settings = config.settings;
      var sepText = widgets[delta].sepText;
      var sepLabel = settings.showLabels ? /*#__PURE__*/React.createElement("label", {
        className: "rule--label"
      }, "\xA0") : null;
      return sepText && /*#__PURE__*/React.createElement("div", {
        key: "widget-separators-" + delta,
        className: classNames("widget--sep", delta == 0 && "widget--sep-first")
      }, sepLabel, /*#__PURE__*/React.createElement("span", null, sepText));
    };
    _this.renderWidgetDelta = function (delta) {
      var sep = _this.renderSep(delta, _this.meta, _this.props);
      var sources = _this.renderValueSources(delta, _this.meta, _this.props);
      var widgetCmp = _this.renderWidget(delta, _this.meta, _this.props);
      return [sep, sources, widgetCmp];
    };
    useOnPropsChanged(_this);
    _this.onPropsChanged(_props);
    return _this;
  }
  _inherits(Widget, _Component);
  return _createClass(Widget, [{
    key: "onPropsChanged",
    value: function onPropsChanged(nextProps) {
      var prevProps = this.props;
      var configChanged = !this.ValueSources || (prevProps === null || prevProps === void 0 ? void 0 : prevProps.config) !== (nextProps === null || nextProps === void 0 ? void 0 : nextProps.config);
      var keysForMeta = ["config", "id", "parentFuncs", "field", "fieldId", "fieldSrc", "fieldType", "fieldFunc", "fieldArg", "leftField", "operator", "valueSrc", "asyncListValues", "isLHS", "isFuncArg", "isForRuleGroup", "isCaseValue", "value"];
      var changedKeys = keysForMeta.filter(function (k) {
        if (k === "parentFuncs") {
          return !shallowEqual(nextProps[k], prevProps[k], true);
        }
        // if (k === "value") {
        //   if (nextProps["value"] !== prevProps["value"] && isImmutable(nextProps["value"])) {
        //   }
        // }
        if (k === "field") {
          //tip: if `fieldId` has not changed, but `field` changed -> ignore
          // (because we are in RHS and field is LHS)
          return nextProps["fieldId"] !== prevProps["fieldId"];
        }
        return nextProps[k] !== prevProps[k];
      });
      var needUpdateMeta = !this.meta || changedKeys.length > 0;
      if (needUpdateMeta) {
        this.meta = this.getMeta(nextProps, changedKeys);
      }
      if (configChanged) {
        var config = nextProps.config;
        var renderValueSources = config.settings.renderValueSources;
        this.ValueSources = getRenderFromConfig(config, renderValueSources);
      }
    }
  }, {
    key: "getMeta",
    value: function getMeta(_ref) {
      var _iValueSrcs,
        _iValueSrcs2,
        _this$meta,
        _this$meta2,
        _this2 = this;
      var config = _ref.config,
        simpleField = _ref.field,
        fieldSrc = _ref.fieldSrc,
        fieldType = _ref.fieldType,
        fieldFunc = _ref.fieldFunc,
        fieldArg = _ref.fieldArg,
        operator = _ref.operator,
        valueSrcs = _ref.valueSrc,
        values = _ref.value,
        isForRuleGroup = _ref.isForRuleGroup,
        isCaseValue = _ref.isCaseValue,
        isFuncArg = _ref.isFuncArg,
        leftField = _ref.leftField,
        asyncListValues = _ref.asyncListValues,
        parentFuncs = _ref.parentFuncs,
        isLHS = _ref.isLHS,
        id = _ref.id;
      var changedKeys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
      var valueSourcesInfo = config.settings.valueSourcesInfo;
      var field = isFuncArg ? {
        func: fieldFunc,
        arg: fieldArg
      } : simpleField;
      var isOkWithoutField = !simpleField && fieldType;
      var iValueSrcs = valueSrcs;
      var iValues = values;
      if (isFuncArg || isForRuleGroup || isCaseValue) {
        iValueSrcs = createListWithOneElement(valueSrcs);
        iValues = createListWithOneElement(values);
      }
      var fieldDefinition = getFieldConfig(config, field);
      if (!fieldDefinition && isOkWithoutField) {
        fieldDefinition = config.types[fieldType];
      }
      var defaultWidget = getWidgetForFieldOp(config, field, operator);
      if (!defaultWidget && isOkWithoutField) {
        var _config$types$fieldTy;
        defaultWidget = (_config$types$fieldTy = config.types[fieldType]) === null || _config$types$fieldTy === void 0 ? void 0 : _config$types$fieldTy.mainWidget;
      }
      var operatorDefinition = isFuncArg ? funcArgDummyOpDef : getOperatorConfig(config, operator, field);
      if ((fieldDefinition == null || operatorDefinition == null) && !isCaseValue) {
        return null;
      }
      var isSpecialRange = operatorDefinition === null || operatorDefinition === void 0 ? void 0 : operatorDefinition.isSpecialRange;
      var isSpecialRangeForSrcField = isSpecialRange && (((_iValueSrcs = iValueSrcs) === null || _iValueSrcs === void 0 ? void 0 : _iValueSrcs.get(0)) === "field" || ((_iValueSrcs2 = iValueSrcs) === null || _iValueSrcs2 === void 0 ? void 0 : _iValueSrcs2.get(1)) === "field");
      var isTrueSpecialRange = isSpecialRange && !isSpecialRangeForSrcField;
      var cardinality = isTrueSpecialRange ? 1 : getOpCardinality(operatorDefinition);
      if (cardinality === 0) {
        return null;
      }
      var valueSources = (_this$meta = this.meta) === null || _this$meta === void 0 ? void 0 : _this$meta.valueSources;
      var valueSourcesOptions = (_this$meta2 = this.meta) === null || _this$meta2 === void 0 ? void 0 : _this$meta2.valueSourcesOptions;
      var defaultValueSourcesLabels = {
        value: "Value",
        field: "Field",
        func: "Function"
      };
      if (!valueSources || ["field", "operator", "config", "fieldDefinition", "isForRuleGroup"].filter(function (k) {
        return changedKeys.includes(k);
      }).length) {
        valueSources = getValueSourcesForFieldOp(config, field, operator, fieldDefinition);
        if (isForRuleGroup) {
          // todo: aggregation can be not only number?
          valueSources = ["value"];
        }
        if (!field) {
          valueSources = Object.keys(valueSourcesInfo);
        }
        valueSourcesOptions = valueSources.map(function (srcKey) {
          var _ref2, _valueSourcesInfo$src, _valueSourcesInfo$src2;
          return [srcKey, {
            label: (_ref2 = (_valueSourcesInfo$src = (_valueSourcesInfo$src2 = valueSourcesInfo[srcKey]) === null || _valueSourcesInfo$src2 === void 0 ? void 0 : _valueSourcesInfo$src2.label) !== null && _valueSourcesInfo$src !== void 0 ? _valueSourcesInfo$src : defaultValueSourcesLabels[srcKey]) !== null && _ref2 !== void 0 ? _ref2 : srcKey
          }];
        });
      }
      var widgets = range(0, cardinality).map(function (delta) {
        var _this2$meta, _iValueSrcs3, _widgetDefinition, _this2$meta2;
        var oldWidgetMeta = (_this2$meta = _this2.meta) === null || _this2$meta === void 0 || (_this2$meta = _this2$meta.widgets) === null || _this2$meta === void 0 ? void 0 : _this2$meta[delta];
        var valueSrc = ((_iValueSrcs3 = iValueSrcs) === null || _iValueSrcs3 === void 0 ? void 0 : _iValueSrcs3.get(delta)) || null;
        var widget = getWidgetForFieldOp(config, field, operator, valueSrc);
        var widgetDefinition = getFieldWidgetConfig(config, field, operator, widget, valueSrc);
        if (isSpecialRangeForSrcField) {
          widget = widgetDefinition.singleWidget;
          widgetDefinition = getFieldWidgetConfig(config, field, operator, widget, valueSrc);
        }
        if (!widgetDefinition && isOkWithoutField) {
          widget = ["func", "field"].includes(valueSrc) ? valueSrc : defaultWidget;
          widgetDefinition = config.widgets[widget];
        }
        var widgetType = (_widgetDefinition = widgetDefinition) === null || _widgetDefinition === void 0 ? void 0 : _widgetDefinition.type;
        var valueLabel = getValueLabel(config, field, operator, delta, valueSrc, isTrueSpecialRange);
        var widgetValueLabel = getValueLabel(config, field, operator, delta, null, isTrueSpecialRange);
        var sepText = operatorDefinition !== null && operatorDefinition !== void 0 && operatorDefinition.textSeparators ? operatorDefinition === null || operatorDefinition === void 0 ? void 0 : operatorDefinition.textSeparators[delta] : null;
        var valueLabels = null;
        var textSeparators = null;
        if (isSpecialRange) {
          valueLabels = [getValueLabel(config, field, operator, 0), getValueLabel(config, field, operator, 1)];
          valueLabels = {
            placeholder: [valueLabels[0].placeholder, valueLabels[1].placeholder],
            label: [valueLabels[0].label, valueLabels[1].label]
          };
          textSeparators = operatorDefinition === null || operatorDefinition === void 0 ? void 0 : operatorDefinition.textSeparators;
        }
        var widgetId = getWidgetId({
          id: id,
          isLHS: isLHS,
          delta: delta,
          parentFuncs: parentFuncs
        });
        var vsId = widgetId + ":" + "VS";
        var setValueSrc = oldWidgetMeta === null || oldWidgetMeta === void 0 ? void 0 : oldWidgetMeta.setValueSrc;
        if (!setValueSrc || (oldWidgetMeta === null || oldWidgetMeta === void 0 ? void 0 : oldWidgetMeta.widgetId) !== widgetId) {
          setValueSrc = _this2._setValueSrc.bind(_this2, delta, vsId);
        }
        var setValue = oldWidgetMeta === null || oldWidgetMeta === void 0 ? void 0 : oldWidgetMeta.setValue;
        if (!setValue || (oldWidgetMeta === null || oldWidgetMeta === void 0 ? void 0 : oldWidgetMeta.widgetId) !== widgetId || (oldWidgetMeta === null || oldWidgetMeta === void 0 ? void 0 : oldWidgetMeta.widgetType) !== widgetType || ((_this2$meta2 = _this2.meta) === null || _this2$meta2 === void 0 ? void 0 : _this2$meta2.isSpecialRange) !== isSpecialRange) {
          setValue = _this2._setValue.bind(_this2, isSpecialRange, delta, widgetType, widgetId);
        }
        return {
          valueSrc: valueSrc,
          valueLabel: valueLabel,
          widget: widget,
          sepText: sepText,
          widgetDefinition: widgetDefinition,
          widgetValueLabel: widgetValueLabel,
          valueLabels: valueLabels,
          textSeparators: textSeparators,
          setValueSrc: setValueSrc,
          setValue: setValue,
          widgetId: widgetId,
          widgetType: widgetType
        };
      });
      return {
        defaultWidget: defaultWidget,
        fieldDefinition: fieldDefinition,
        operatorDefinition: operatorDefinition,
        isSpecialRange: isTrueSpecialRange,
        cardinality: cardinality,
        valueSources: valueSources,
        valueSourcesOptions: valueSourcesOptions,
        widgets: widgets,
        iValues: iValues,
        //correct for isFuncArg
        aField: field,
        //correct for isFuncArg
        asyncListValues: asyncListValues
      };
    }
  }, {
    key: "render",
    value: function render() {
      if (!this.meta) return null;
      var _this$meta3 = this.meta,
        defaultWidget = _this$meta3.defaultWidget,
        cardinality = _this$meta3.cardinality;
      if (!defaultWidget) return null;
      var name = defaultWidget;
      return /*#__PURE__*/React.createElement(Col, {
        className: "rule--widget rule--widget--".concat(name.toUpperCase()),
        key: "widget-col-" + name
      }, range(0, cardinality).map(this.renderWidgetDelta));
    }
  }]);
}(Component);
Widget.propTypes = {
  config: PropTypes.object.isRequired,
  value: PropTypes.any,
  //instanceOf(Immutable.List)
  valueSrc: PropTypes.any,
  //instanceOf(Immutable.List)
  valueError: PropTypes.any,
  //instanceOf(Immutable.List)
  fieldError: PropTypes.string,
  field: PropTypes.any,
  fieldSrc: PropTypes.string,
  fieldType: PropTypes.string,
  fieldId: PropTypes.string,
  operator: PropTypes.string,
  readonly: PropTypes.bool,
  asyncListValues: PropTypes.array,
  id: PropTypes.string,
  groupId: PropTypes.string,
  //actions
  setValue: PropTypes.func,
  setValueSrc: PropTypes.func,
  setFuncValue: PropTypes.func,
  // for isFuncArg
  isFuncArg: PropTypes.bool,
  fieldFunc: PropTypes.string,
  fieldArg: PropTypes.string,
  leftField: PropTypes.any,
  // for RuleGroupExt
  isForRuleGroup: PropTypes.bool,
  parentField: PropTypes.string,
  // for func in func
  parentFuncs: PropTypes.array,
  isLHS: PropTypes.bool,
  // for case_value
  isCaseValue: PropTypes.bool
};
export { Widget as default };