"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.stringOperatorFilter = exports.operatorNeedsValue = exports.operatorFilter = exports.OperatorFilterState = exports.DEFAULT_OPERATOR_ORDER = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _events = require("events");
var _mobx = require("mobx");
var _model = require("../../model");
var _refreshFilter = require("../Filter/refreshFilter");
var _operatorLabels = require("../../util/operatorLabels");
/**
 * Check if an operator requires a value input.
 * Operators that don't need a value (IS_EMPTY, EXISTS, NOT_EXISTS) are
 * immediately "active" when selected, so they have no neutral "zero state".
 */
const operatorNeedsValue = operator => operator !== _model.FilterOperator.IS_EMPTY && operator !== _model.FilterOperator.EXISTS && operator !== _model.FilterOperator.NOT_EXISTS;

/**
 * Standard operator ordering for UI display.
 * This is the default ordering applied when `operatorOrderOverride` is not set.
 */
exports.operatorNeedsValue = operatorNeedsValue;
const DEFAULT_OPERATOR_ORDER = exports.DEFAULT_OPERATOR_ORDER = [_model.FilterOperator.EQUALS, _model.FilterOperator.NOT_EQUALS, _model.FilterOperator.IN, _model.FilterOperator.NOT_IN, _model.FilterOperator.CONTAINS, _model.FilterOperator.NOT_CONTAINS, _model.FilterOperator.STARTS_WITH, _model.FilterOperator.IS_EMPTY, _model.FilterOperator.EXISTS, _model.FilterOperator.NOT_EXISTS];

/**
 * Reorder operators according to `DEFAULT_OPERATOR_ORDER`, keeping only the
 * ones present in `operators`.
 */
const reorderOperators = operators => DEFAULT_OPERATOR_ORDER.filter(op => operators.includes(op));

/**
 * Validate that the first (default) operator has a zero state.
 * Only called when `operatorOrderOverride` is `true`.
 * If invalid, falls back to the default ordering and logs an error.
 */
const validateDefaultOperator = (operators, filterName) => {
  if (operators.length === 0) {
    return operators;
  }
  const first = operators[0];
  if (!operatorNeedsValue(first)) {
    if (process.env.NODE_ENV !== 'production') {
      // eslint-disable-next-line no-console
      console.error(`[OperatorFilterState] Invalid default operator "${first}" for filter "${filterName}": ` + `Operators that don't require a value (e.g. EXISTS, NOT_EXISTS, IS_EMPTY) ` + `cannot be the default operator because the filter would start in an active state. ` + `Falling back to the default operator order.`);
    }
    return reorderOperators(operators);
  }
  return operators;
};
class OperatorFilterState {
  constructor(params) {
    (0, _defineProperty2.default)(this, "name", void 0);
    (0, _defineProperty2.default)(this, "persistent", void 0);
    (0, _defineProperty2.default)(this, "_value", undefined);
    (0, _defineProperty2.default)(this, "allowedOperators", void 0);
    (0, _defineProperty2.default)(this, "operatorOrderOverride", void 0);
    (0, _defineProperty2.default)(this, "itemKey", void 0);
    (0, _defineProperty2.default)(this, "itemName", void 0);
    (0, _defineProperty2.default)(this, "equals", void 0);
    (0, _defineProperty2.default)(this, "matches", void 0);
    (0, _defineProperty2.default)(this, "decode", void 0);
    (0, _defineProperty2.default)(this, "encode", void 0);
    (0, _defineProperty2.default)(this, "events", new _events.EventEmitter());
    this.name = params.name ?? '';
    this.persistent = params.persistent;
    this.operatorOrderOverride = params.operatorOrderOverride ?? false;
    this.allowedOperators = this.operatorOrderOverride ? validateDefaultOperator(params.allowedOperators, this.name) : reorderOperators(params.allowedOperators);
    this._value = params.initialValue ?? {
      operator: this.allowedOperators[0],
      value: null
    };
    this.itemKey = params.itemKey ?? (item => {
      return `${item.operator}:${item.value}`;
    });
    this.itemName = params.itemName ?? (item => {
      const operatorLabel = (0, _operatorLabels.getOperatorLabel)(item.operator);
      return `${operatorLabel}${item.value != null && item.value !== '' ? `  ${item.value}` : ''}`;
    });
    this.matches = params.matches ?? ((item, filterValue) => {
      const operator = filterValue.operator;
      const value = filterValue.value;
      const itemValue = item.value;
      if (operator === _model.FilterOperator.IS_EMPTY) {
        return itemValue === null || itemValue === '' || itemValue === undefined;
      }
      if (value === null) {
        return false;
      }
      if (operator === _model.FilterOperator.EXISTS) {
        return itemValue !== null && itemValue !== undefined;
      }
      if (operator === _model.FilterOperator.NOT_EXISTS) {
        return itemValue === null || itemValue === undefined;
      }
      if (typeof itemValue === 'string' && typeof value === 'string') {
        const itemStr = itemValue.toLowerCase();
        const valueStr = value.toLowerCase();
        switch (operator) {
          case _model.FilterOperator.EQUALS:
            return itemStr === valueStr;
          case _model.FilterOperator.NOT_EQUALS:
            return itemStr !== valueStr;
          case _model.FilterOperator.STARTS_WITH:
            return itemStr.startsWith(valueStr);
          case _model.FilterOperator.CONTAINS:
            return itemStr.includes(valueStr);
          case _model.FilterOperator.NOT_CONTAINS:
            return !itemStr.includes(valueStr);
        }
      }
      return itemValue === value;
    });
    this.equals = params.equals ?? ((item1, item2) => {
      if (item1.operator !== item2.operator) {
        return false;
      }
      return item1.value === item2.value;
    });
    this.encode = params.encode ?? (value => ({
      operator: value.operator,
      value: value.value
    }));
    this.decode = params.decode ?? (value => {
      var _this$_value;
      if (value) {
        return {
          operator: value.operator,
          value: value.value
        };
      }
      return {
        operator: (_this$_value = this._value) == null ? void 0 : _this$_value.operator,
        value: null
      };
    });
    (0, _mobx.makeObservable)(this, {
      _value: _mobx.observable.ref,
      persistent: _mobx.observable.ref,
      isEmpty: _mobx.computed,
      size: _mobx.computed,
      value: _mobx.computed,
      reset: _mobx.action,
      setValue: _mobx.action,
      changeValue: _mobx.action,
      scheduleRefresh: _mobx.action,
      setOperator: _mobx.action,
      setFilterValue: _mobx.action,
      clone: _mobx.action
    });
  }
  get value() {
    return this._value;
  }
  get toArray() {
    return this._toArray(this._value);
  }
  get _toArray() {
    return value => {
      if (this.isEmpty) {
        return [];
      }
      return [value];
    };
  }
  get isEmpty() {
    if (!this._value) {
      return true;
    }
    if (!operatorNeedsValue(this._value.operator)) {
      return false;
    }
    return this._value.value === null || this._value.value === '';
  }

  /** Computed default operator - first in allowedOperators */
  get defaultOperator() {
    return this.allowedOperators[0];
  }
  get size() {
    return this.isEmpty ? 0 : 1;
  }
  setValue(value, {
    emitEvents,
    ...options
  } = {}) {
    this._value = value;
    if (emitEvents) {
      for (const event of emitEvents) {
        this.events.emit(event, options);
      }
    }
  }
  changeValue(value, {
    emitEvents = [],
    ...options
  } = {}) {
    this.setValue(value, {
      ...options,
      emitEvents: ['change', ...emitEvents]
    });
  }
  refresh(value, options) {
    (0, _refreshFilter.refreshFilter)(this, value, options);
  }
  scheduleRefresh(value) {
    this.changeValue(value, {
      emitEvents: ['scheduleRefresh']
    });
  }

  /**
   * Set only the operator, keeping the current value
   */
  setOperator(operator, options) {
    var _this$_value2;
    this.changeValue({
      operator,
      value: ((_this$_value2 = this._value) == null ? void 0 : _this$_value2.value) ?? null
    }, options);
  }

  /**
   * Set only the filter value, keeping the current operator
   */
  setFilterValue(value, options) {
    this.changeValue({
      operator: this._value.operator,
      value
    }, options);
  }
  get toQueryString() {
    return JSON.stringify(this.encode(this.value));
  }
  applyFromQueryString(str) {
    try {
      const raw = JSON.parse(str);
      this.setValue(this.decode(raw));
    } catch (e) {
      // Invalid JSON, reset to default
      this.reset();
    }
  }
  reset(options = {}) {
    this._value = {
      operator: this.defaultOperator,
      value: null
    };
    if (options.emitEvents) {
      for (const event of options.emitEvents) {
        this.events.emit(event, options);
      }
    }
  }
  remove(_items, options = {}) {
    this.reset(options);
  }
  hasDiff(data) {
    return data.operator !== this.value.operator || data.value !== this.value.value;
  }
  clone(params = {}) {
    return new OperatorFilterState({
      name: this.name,
      persistent: this.persistent,
      itemKey: this.itemKey,
      itemName: this.itemName,
      equals: this.equals,
      encode: this.encode,
      decode: this.decode,
      matches: this.matches,
      allowedOperators: this.allowedOperators,
      operatorOrderOverride: this.operatorOrderOverride,
      ...params
    });
  }
}
exports.OperatorFilterState = OperatorFilterState;
const operatorFilter = params => new OperatorFilterState(params);
exports.operatorFilter = operatorFilter;
const stringOperatorFilter = params => new OperatorFilterState(params);
exports.stringOperatorFilter = stringOperatorFilter;
//# sourceMappingURL=OperatorFilterState.js.map