import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _extends from "@babel/runtime/helpers/esm/extends";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import * as React from 'react';
import { GridSignature } from '../utils/useGridApiEventHandler';
import { useGridApiMethod } from '../utils';
import { isFunction } from '../../utils/utils';
export var useGridStateInitialization = function useGridStateInitialization(apiRef, props) {
  var controlStateMapRef = React.useRef({});
  var _React$useState = React.useState(),
    _React$useState2 = _slicedToArray(_React$useState, 2),
    rawForceUpdate = _React$useState2[1];
  var registerControlState = React.useCallback(function (controlStateItem) {
    controlStateMapRef.current[controlStateItem.stateId] = controlStateItem;
  }, []);
  var setState = React.useCallback(function (state, reason) {
    var newState;
    if (isFunction(state)) {
      newState = state(apiRef.current.state);
    } else {
      newState = state;
    }
    if (apiRef.current.state === newState) {
      return false;
    }
    var ignoreSetState = false;

    // Apply the control state constraints
    var updatedControlStateIds = [];
    Object.keys(controlStateMapRef.current).forEach(function (stateId) {
      var controlState = controlStateMapRef.current[stateId];
      var oldSubState = controlState.stateSelector(apiRef.current.state, apiRef.current.instanceId);
      var newSubState = controlState.stateSelector(newState, apiRef.current.instanceId);
      if (newSubState === oldSubState) {
        return;
      }
      updatedControlStateIds.push({
        stateId: controlState.stateId,
        hasPropChanged: newSubState !== controlState.propModel
      });

      // The state is controlled, the prop should always win
      if (controlState.propModel !== undefined && newSubState !== controlState.propModel) {
        ignoreSetState = true;
      }
    });
    if (updatedControlStateIds.length > 1) {
      // Each hook modify its own state, and it should not leak
      // Events are here to forward to other hooks and apply changes.
      // You are trying to update several states in a no isolated way.
      throw new Error("You're not allowed to update several sub-state in one transaction. You already updated ".concat(updatedControlStateIds[0].stateId, ", therefore, you're not allowed to update ").concat(updatedControlStateIds.map(function (el) {
        return el.stateId;
      }).join(', '), " in the same transaction."));
    }
    if (!ignoreSetState) {
      // We always assign it as we mutate rows for perf reason.
      apiRef.current.state = newState;
      if (apiRef.current.publishEvent) {
        apiRef.current.publishEvent('stateChange', newState);
      }
      apiRef.current.store.update(newState);
    }
    if (updatedControlStateIds.length === 1) {
      var _updatedControlStateI = updatedControlStateIds[0],
        stateId = _updatedControlStateI.stateId,
        hasPropChanged = _updatedControlStateI.hasPropChanged;
      var controlState = controlStateMapRef.current[stateId];
      var model = controlState.stateSelector(newState, apiRef.current.instanceId);
      if (controlState.propOnChange && hasPropChanged) {
        var details = props.signature === GridSignature.DataGridPro ? {
          api: apiRef.current,
          reason: reason
        } : {
          reason: reason
        };
        controlState.propOnChange(model, details);
      }
      if (!ignoreSetState) {
        apiRef.current.publishEvent(controlState.changeEvent, model, {
          reason: reason
        });
      }
    }
    return !ignoreSetState;
  }, [apiRef, props.signature]);
  var updateControlState = React.useCallback(function (key, state, reason) {
    return apiRef.current.setState(function (previousState) {
      return _extends({}, previousState, _defineProperty({}, key, state(previousState[key])));
    }, reason);
  }, [apiRef]);
  var forceUpdate = React.useCallback(function () {
    return rawForceUpdate(function () {
      return apiRef.current.state;
    });
  }, [apiRef]);
  var publicStateApi = {
    setState: setState,
    forceUpdate: forceUpdate
  };
  var privateStateApi = {
    updateControlState: updateControlState,
    registerControlState: registerControlState
  };
  useGridApiMethod(apiRef, publicStateApi, 'public');
  useGridApiMethod(apiRef, privateStateApi, 'private');
};