import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import warning from "rc-util/es/warning";
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
import FieldContext, { HOOK_MARK } from "./FieldContext";
import { isFormInstance } from "./utils/typeUtil";
import { getNamePath, getValue } from "./utils/valueUtil";
export function stringify(value) {
  try {
    return JSON.stringify(value);
  } catch (err) {
    return Math.random();
  }
}
var useWatchWarning = process.env.NODE_ENV !== 'production' ? function (namePath) {
  var fullyStr = namePath.join('__RC_FIELD_FORM_SPLIT__');
  var nameStrRef = useRef(fullyStr);
  warning(nameStrRef.current === fullyStr, '`useWatch` is not support dynamic `namePath`. Please provide static instead.');
} : function () {};

// ------- selector type -------

// ------- selector type end -------

function useWatch() {
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
    args[_key] = arguments[_key];
  }
  var dependencies = args[0],
    _args$ = args[1],
    _form = _args$ === void 0 ? {} : _args$;
  var options = isFormInstance(_form) ? {
    form: _form
  } : _form;
  var form = options.form;
  var _useState = useState(),
    _useState2 = _slicedToArray(_useState, 2),
    value = _useState2[0],
    setValue = _useState2[1];
  var valueStr = useMemo(function () {
    return stringify(value);
  }, [value]);
  var valueStrRef = useRef(valueStr);
  valueStrRef.current = valueStr;
  var fieldContext = useContext(FieldContext);
  var formInstance = form || fieldContext;
  var isValidForm = formInstance && formInstance._init;

  // Warning if not exist form instance
  if (process.env.NODE_ENV !== 'production') {
    warning(args.length === 2 ? form ? isValidForm : true : isValidForm, 'useWatch requires a form instance since it can not auto detect from context.');
  }
  var namePath = getNamePath(dependencies);
  var namePathRef = useRef(namePath);
  namePathRef.current = namePath;
  useWatchWarning(namePath);
  useEffect(function () {
    // Skip if not exist form instance
    if (!isValidForm) {
      return;
    }
    var getFieldsValue = formInstance.getFieldsValue,
      getInternalHooks = formInstance.getInternalHooks;
    var _getInternalHooks = getInternalHooks(HOOK_MARK),
      registerWatch = _getInternalHooks.registerWatch;
    var getWatchValue = function getWatchValue(values, allValues) {
      var watchValue = options.preserve ? allValues : values;
      return typeof dependencies === 'function' ? dependencies(watchValue) : getValue(watchValue, namePathRef.current);
    };
    var cancelRegister = registerWatch(function (values, allValues) {
      var newValue = getWatchValue(values, allValues);
      var nextValueStr = stringify(newValue);

      // Compare stringify in case it's nest object
      if (valueStrRef.current !== nextValueStr) {
        valueStrRef.current = nextValueStr;
        setValue(newValue);
      }
    });

    // TODO: We can improve this perf in future
    var initialValue = getWatchValue(getFieldsValue(), getFieldsValue(true));

    // React 18 has the bug that will queue update twice even the value is not changed
    // ref: https://github.com/facebook/react/issues/27213
    if (value !== initialValue) {
      setValue(initialValue);
    }
    return cancelRegister;
  },
  // We do not need re-register since namePath content is the same
  // eslint-disable-next-line react-hooks/exhaustive-deps
  [isValidForm]);
  return value;
}
export default useWatch;