"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useSharedPluginStateSelector = useSharedPluginStateSelector;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray"));
var _react = require("react");
var _get = _interopRequireDefault(require("lodash/get"));
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
var _usePluginStateEffect = require("../usePluginStateEffect");
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any

/**
 * This is designed to iterate through an object to get the path of its result
 * based on separation via "."
 *
 * Example:
 * ```typescript
 * type Test = { deepObject: { value: number } };
 * // Type should be `"deepObject" | "deepObject.value"`
 * type Result = NestedKeys<Test>;
 * ```
 */

/**
 * This is designed to iterate through a path of an object to get the type of its result
 * based on separation via "."
 *
 * Example:
 * ```typescript
 * type Test = { deepObject: { value: number } }
 * // Type should be `number`
 * type Result = Path<Test, 'deepObject.value'>
 * ```
 */

/**
 *
 * NOTE: Generally you want to use `useSharedPluginStateWithSelector` over this which behaves similarly
 * but selects a slice of the state which is more performant.
 *
 * ⚠️⚠️⚠️ This is a debounced hook ⚠️⚠️⚠️
 * If the plugins you are listening to generate multiple shared states while the user is typing,
 * your React Component will get only the last one.
 *
 * Used to return the current plugin state of input dependencies.
 * It will recursively retrieve a slice of the state using a "." to separate
 * parts of the state.
 *
 * Example:
 *
 * ```typescript
 * 	const pluginA: NextEditorPlugin<
		'pluginA',
		{
			sharedState: { deepObj: { value: number | undefined } };
		}
	>
 * ```
 * You can use `const value = useSharedPluginStateSelector(api, 'pluginA.deepObj.value')` to retrieve the value
 *
 * Example in plugin:
 *
 * ```typescript
 * function ExampleContent({ api }: Props) {
 *   const title = useSharedPluginStateSelector(api, 'dog.title')
 *   return <p>{ title } { exampleState.description }</p>
 * }
 *
 * const examplePlugin: NextEditorPlugin<'example', { dependencies: [typeof pluginDog] }> = ({ api }) => {
 *   return {
 *     name: 'example',
 *     contentComponent: () => <ExampleContent api={api} />
 *   }
 * }
 * ```
 *
 * NOTE: If you pass an invalid path, `undefined` will be returned
 *
 * @param api
 * @param plugin
 * @param options
 * @returns
 */
function useSharedPluginStateSelector(api, plugin) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
  var transformer = (0, _react.useCallback)(function (pluginState) {
    var _plugin$split = plugin.split('.'),
      _plugin$split2 = (0, _toArray2.default)(_plugin$split),
      pluginName = _plugin$split2[0],
      properties = _plugin$split2.slice(1);
    if (!pluginState || (properties === null || properties === void 0 ? void 0 : properties.length) === 0) {
      return undefined;
    }
    return (0, _get.default)(pluginState === null || pluginState === void 0 ? void 0 : pluginState["".concat(pluginName, "State")], properties);
  }, [plugin]);
  var pluginNameArray = (0, _react.useMemo)(function () {
    var _plugin$split3 = plugin.split('.'),
      _plugin$split4 = (0, _slicedToArray2.default)(_plugin$split3, 1),
      pluginName = _plugin$split4[0];
    return [pluginName];
  }, [plugin]);
  var initialState = (0, _react.useMemo)(function () {
    var _api$pluginName;
    if (options.disabled) {
      return;
    }
    var _plugin$split5 = plugin.split('.'),
      _plugin$split6 = (0, _slicedToArray2.default)(_plugin$split5, 1),
      pluginName = _plugin$split6[0];
    return transformer((0, _defineProperty2.default)({}, "".concat(pluginName, "State"), api === null || api === void 0 || (_api$pluginName = api[pluginName]) === null || _api$pluginName === void 0 ? void 0 : _api$pluginName.sharedState.currentState()));
  }, [plugin, api, options.disabled, transformer]);
  return useSharedPluginStateSelectorInternal(api, pluginNameArray, transformer, initialState, options);
}
function useSharedPluginStateSelectorInternal(api, plugins, transformer, initialState) {
  var options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
  var _useState = (0, _react.useState)(function () {
      return initialState;
    }),
    _useState2 = (0, _slicedToArray2.default)(_useState, 2),
    selectedPluginState = _useState2[0],
    setSelectedPluginState = _useState2[1];
  (0, _usePluginStateEffect.usePluginStateEffect)(api, plugins, function (pluginStates) {
    // `pluginStates`: This is the same type through inference - but typescript doesn't recognise them as they are computed slightly differently
    var transformedValue = transformer(pluginStates);
    if (!(0, _isEqual.default)(transformedValue, selectedPluginState)) {
      setSelectedPluginState(function () {
        return transformedValue;
      });
    }
  }, options);
  return selectedPluginState;
}