import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose";
import _wrapNativeSuper from "@babel/runtime/helpers/esm/wrapNativeSuper";
import { isValidElement } from 'react';
import { isForwardRef } from 'react-is';
import { globalObject, isBrowser } from '@skbkontur/global-object';
export { delay } from "../delay";

// NOTE: Copy-paste from @types/react

export var emptyHandler = function emptyHandler() {

  /* noop */};
export var CancelationError = /*#__PURE__*/function (_Error) {
  function CancelationError() {
    var _this;
    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }
    _this = _Error.call.apply(_Error, [this].concat(args)) || this;
    _this.code = 'CancelationError';
    return _this;
  }
  _inheritsLoose(CancelationError, _Error);
  return CancelationError;
}( /*#__PURE__*/_wrapNativeSuper(Error));
export function taskWithDelay(task, ms) {
  var cancelationToken = function cancelationToken() {
    return null;
  };
  new Promise(function (resolve, reject) {
    cancelationToken = reject;
    globalObject.setTimeout(resolve, ms);
  }).then(task)["catch"](function () {
    return null;
  });
  return cancelationToken;
}
export function isFunction(x) {
  return typeof x === 'function';
}
export function isFunctionalComponent(Component) {
  return Boolean(typeof Component === 'function' && !(Component.prototype && Component.prototype.isReactComponent));
}
export function isClassComponent(Component) {
  return Boolean(typeof Component === 'function' && Component.prototype && Component.prototype.isReactComponent);
}
export function isIntrinsicElement(element) {
  return typeof element.type === 'string';
}
export function isRefableElement(element) {
  return Boolean(isIntrinsicElement(element) || isClassComponent(element.type) || isForwardRef(element));
}
export function escapeRegExpSpecChars(s) {
  return s.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
}
export var getRandomID = function getRandomID() {
  return Math.random().toString(16).slice(2);
};
export var isExternalLink = function isExternalLink(link) {
  return isBrowser(globalObject) && new RegExp("^(https?:)?//(?!" + globalObject.location.host + ")\\S+", 'gi').test(link);
};

/**
 * Check if the given ReactNode is an element of the specified ReactUI component
 */
export var isReactUINode = function isReactUINode(componentName, node) {
  if ( /*#__PURE__*/isValidElement(node)) {
    return Object.prototype.hasOwnProperty.call(node.type, '__KONTUR_REACT_UI__') &&
    // @ts-expect-error: React doesn't know about existence of __KONTUR_REACT_UI__.
    node.type.__KONTUR_REACT_UI__ === componentName;
  }
  return false;
};
var KB = 1024;
var UNITS = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
var calculateDecimals = function calculateDecimals(decimals) {
  if (decimals < 0) {
    return 0;
  }
  return 0;
};
export var formatBytes = function formatBytes(bytes, decimals) {
  if (decimals === void 0) {
    decimals = 2;
  }
  if (bytes === 0) {
    return '0 Bytes';
  }
  if (!bytes) {
    return null;
  }
  var calculatedDecimals = calculateDecimals(decimals);
  var i = Math.floor(Math.log2(bytes) / Math.log2(KB));
  var formattedBytes = parseFloat((bytes / Math.pow(KB, i)).toFixed(calculatedDecimals));
  return formattedBytes + " " + UNITS[i];
};

/**
 * Проверяет, не является ли переданный аргумент null или undefined и исключает типы null и undefined из типа аргумента
 *
 * @param value Значение, которое нужно проверить и исключить из него типы
 * @returns Возвращает true, если переданный аргумент не является null или undefined иначе false
 */
export var isNonNullable = function isNonNullable(value) {
  return value !== null && value !== undefined;
};

/**
 * Checks if the value `null` or `undefined`.
 *
 * @param value Value to check for `null` and `undefined`.
 * @returns Returns `true` if `value` is `null` or `undefined`, else `false`.
 */
export var isNullable = function isNullable(value) {
  return value === null || value === undefined;
};

/**
 * Creates a function that checks if the given `child`
 * is an instance of some component specified by `name`.
 *
 * @param name Component name for which function will be created.
 * @returns A function that checks if the given `child` is an instance of the component specified by `name`.
 */
export var isReactUIComponent = function isReactUIComponent(name) {
  return function (child) {
    var _child$type;
    // @ts-expect-error: Property `type` doesn't exist on type `React.ReactNode`, but exists on type `React.ReactElement` meanwhile `React.ReactElement` is not compatible with `React` `children` type.
    return (child == null || (_child$type = child.type) == null ? void 0 : _child$type.__KONTUR_REACT_UI__) === name;
  };
};

/**
 * Checks if a component instance is a ReactUI component with the given name.
 *
 * @typeParam T Expected ReactUI component type.
 * @param instance Component instance.
 * @param componentName ReactUI component name.
 * @returns `true` if it matches, otherwise `false`.
 */
export var isReactUIInstance = function isReactUIInstance(instance, componentName) {
  var constructor = instance == null ? void 0 : instance.constructor;
  return '__KONTUR_REACT_UI__' in constructor && constructor.__KONTUR_REACT_UI__ === componentName;
};

/** @deprecated Переехал в `lib/mergeRefs.ts`. Со следующей мажорной версии от сюда будет удален*/
export function mergeRefs(refs) {
  return function (value) {
    refs.forEach(function (ref) {
      if (typeof ref === 'function') {
        return ref(value);
      } else if (isNonNullable(ref)) {
        return ref.current = value;
      }
    });
  };
}

/**
 * Extracts all data attributes from props and returns them as well as props.
 *
 * @param props Props object to extract data attributes from.
 * @returns Separated data attributes and all other props.
 */
export var extractDataProps = function extractDataProps(props) {
  var dataProps = {};
  var restWithoutDataProps = {};
  Object.entries(props).map(function (_ref) {
    var name = _ref[0],
      value = _ref[1];
    if (name.startsWith('data-')) {
      return dataProps[name] = value;
    }
    return restWithoutDataProps[name] = value;
  });
  return {
    dataProps: dataProps,
    restWithoutDataProps: restWithoutDataProps
  };
};

/**
 * Basically `.startsWith` for arrays.
 *
 * @param searchKeys Array of strings to test against `inputString`.
 * @param inputString String on which search will be performed.
 * @returns `true` if `inputString` starts with one of keys, else `false`.
 */
export var startsWithOneOf = function startsWithOneOf(searchKeys, inputString) {
  var keyIndex = searchKeys.findIndex(function (key) {
    return inputString.startsWith(key);
  });
  return keyIndex >= 0;
};
export var isButton = isReactUIComponent('Button');
export var isInput = isReactUIComponent('Input');
export var isFxInput = isReactUIComponent('FxInput');
export var isAutocomplete = isReactUIComponent('Autocomplete');
export var isPasswordInput = isReactUIComponent('PasswordInput');
export var isCurrencyInput = isReactUIComponent('CurrencyInput');
export var isSelect = isReactUIComponent('Select');
export var isDropdown = isReactUIComponent('Dropdown');
export var isDropdownMenu = isReactUIComponent('DropdownMenu');
export var isHint = isReactUIComponent('Hint');
export var isTooltip = isReactUIComponent('Tooltip');
export var isKonturIcon = function isKonturIcon(icon) {
  return Object.prototype.hasOwnProperty.call(icon == null ? void 0 : icon.type, '__KONTUR_ICON__');
};
export function clickOutside(eventType) {
  if (eventType === void 0) {
    eventType = 'mousedown';
  }
  var event = document.createEvent('HTMLEvents');
  event.initEvent(eventType, true, true);
  document.body.dispatchEvent(event);
}
export function isElement(el) {
  return !!el && typeof el === 'object' && 'nodeType' in el && el.nodeType === Node.ELEMENT_NODE;
}
export function isDocument(node) {
  return !!node && typeof node === 'object' && node.nodeType === Node.DOCUMENT_NODE;
}
export function isWindow(node) {
  return !!node && typeof node === 'object' && node.window === node;
}
export function tryGetDocument(node) {
  return !!node && isDocument(node.ownerDocument) ? node.ownerDocument : null;
}
export function tryGetWindow(node) {
  var doc = tryGetDocument(node);
  return isDocument(doc) ? doc.defaultView : null;
}