import _extends from "@babel/runtime/helpers/esm/extends";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import * as React from 'react';
import { unstable_useControlled as useControlled } from '@mui/utils';
import useEventCallback from '@mui/utils/useEventCallback';
import { useOpenState } from '../useOpenState';
import { useLocalizationContext, useUtils } from '../useUtils';
import { useValidation } from '../useValidation';
import { useValueWithTimezone } from '../useValueWithTimezone';

/**
 * Decide if the new value should be published
 * The published value will be passed to `onChange` if defined.
 */
var shouldPublishValue = function shouldPublishValue(params) {
  var action = params.action,
    hasChanged = params.hasChanged,
    dateState = params.dateState,
    isControlled = params.isControlled;
  var isCurrentValueTheDefaultValue = !isControlled && !dateState.hasBeenModifiedSinceMount;

  // The field is responsible for only calling `onChange` when needed.
  if (action.name === 'setValueFromField') {
    return true;
  }
  if (action.name === 'setValueFromAction') {
    // If the component is not controlled, and the value has not been modified since the mount,
    // Then we want to publish the default value whenever the user pressed the "Accept", "Today" or "Clear" button.
    if (isCurrentValueTheDefaultValue && ['accept', 'today', 'clear'].includes(action.pickerAction)) {
      return true;
    }
    return hasChanged(dateState.lastPublishedValue);
  }
  if (action.name === 'setValueFromView' && action.selectionState !== 'shallow') {
    // On the first view,
    // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onChange`
    if (isCurrentValueTheDefaultValue) {
      return true;
    }
    return hasChanged(dateState.lastPublishedValue);
  }
  if (action.name === 'setValueFromShortcut') {
    // On the first view,
    // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onChange`
    if (isCurrentValueTheDefaultValue) {
      return true;
    }
    return hasChanged(dateState.lastPublishedValue);
  }
  return false;
};

/**
 * Decide if the new value should be committed.
 * The committed value will be passed to `onAccept` if defined.
 * It will also be used as a reset target when calling the `cancel` picker action (when clicking on the "Cancel" button).
 */
var shouldCommitValue = function shouldCommitValue(params) {
  var action = params.action,
    hasChanged = params.hasChanged,
    dateState = params.dateState,
    isControlled = params.isControlled,
    closeOnSelect = params.closeOnSelect;
  var isCurrentValueTheDefaultValue = !isControlled && !dateState.hasBeenModifiedSinceMount;
  if (action.name === 'setValueFromAction') {
    // If the component is not controlled, and the value has not been modified since the mount,
    // Then we want to commit the default value whenever the user pressed the "Accept", "Today" or "Clear" button.
    if (isCurrentValueTheDefaultValue && ['accept', 'today', 'clear'].includes(action.pickerAction)) {
      return true;
    }
    return hasChanged(dateState.lastCommittedValue);
  }
  if (action.name === 'setValueFromView' && action.selectionState === 'finish' && closeOnSelect) {
    // On picker where the 1st view is also the last view,
    // If the value is not controlled, then clicking on any value (including the one equal to `defaultValue`) should call `onAccept`
    if (isCurrentValueTheDefaultValue) {
      return true;
    }
    return hasChanged(dateState.lastCommittedValue);
  }
  if (action.name === 'setValueFromShortcut') {
    return action.changeImportance === 'accept' && hasChanged(dateState.lastCommittedValue);
  }
  return false;
};

/**
 * Decide if the picker should be closed after the value is updated.
 */
var shouldClosePicker = function shouldClosePicker(params) {
  var action = params.action,
    closeOnSelect = params.closeOnSelect;
  if (action.name === 'setValueFromAction') {
    return true;
  }
  if (action.name === 'setValueFromView') {
    return action.selectionState === 'finish' && closeOnSelect;
  }
  if (action.name === 'setValueFromShortcut') {
    return action.changeImportance === 'accept';
  }
  return false;
};

/**
 * Manage the value lifecycle of all the pickers.
 */
export var usePickerValue = function usePickerValue(_ref) {
  var props = _ref.props,
    valueManager = _ref.valueManager,
    valueType = _ref.valueType,
    wrapperVariant = _ref.wrapperVariant,
    validator = _ref.validator;
  var onAccept = props.onAccept,
    onChange = props.onChange,
    inValue = props.value,
    inDefaultValue = props.defaultValue,
    _props$closeOnSelect = props.closeOnSelect,
    closeOnSelect = _props$closeOnSelect === void 0 ? wrapperVariant === 'desktop' : _props$closeOnSelect,
    selectedSectionsProp = props.selectedSections,
    onSelectedSectionsChange = props.onSelectedSectionsChange,
    timezoneProp = props.timezone;
  var _React$useRef = React.useRef(inDefaultValue),
    defaultValue = _React$useRef.current;
  var _React$useRef2 = React.useRef(inValue !== undefined),
    isControlled = _React$useRef2.current;

  /* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
  if (process.env.NODE_ENV !== 'production') {
    React.useEffect(function () {
      if (isControlled !== (inValue !== undefined)) {
        console.error(["MUI: A component is changing the ".concat(isControlled ? '' : 'un', "controlled value of a picker to be ").concat(isControlled ? 'un' : '', "controlled."), 'Elements should not switch from uncontrolled to controlled (or vice versa).', "Decide between using a controlled or uncontrolled value" + 'for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
      }
    }, [inValue]);
    React.useEffect(function () {
      if (!isControlled && defaultValue !== inDefaultValue) {
        console.error(["MUI: A component is changing the defaultValue of an uncontrolled picker after being initialized. " + "To suppress this warning opt to use a controlled value."].join('\n'));
      }
    }, [JSON.stringify(defaultValue)]);
  }
  /* eslint-enable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */

  var utils = useUtils();
  var adapter = useLocalizationContext();
  var _useControlled = useControlled({
      controlled: selectedSectionsProp,
      default: null,
      name: 'usePickerValue',
      state: 'selectedSections'
    }),
    _useControlled2 = _slicedToArray(_useControlled, 2),
    selectedSections = _useControlled2[0],
    setSelectedSections = _useControlled2[1];
  var _useOpenState = useOpenState(props),
    isOpen = _useOpenState.isOpen,
    setIsOpen = _useOpenState.setIsOpen;
  var _React$useState = React.useState(function () {
      var initialValue;
      if (inValue !== undefined) {
        initialValue = inValue;
      } else if (defaultValue !== undefined) {
        initialValue = defaultValue;
      } else {
        initialValue = valueManager.emptyValue;
      }
      return {
        draft: initialValue,
        lastPublishedValue: initialValue,
        lastCommittedValue: initialValue,
        lastControlledValue: inValue,
        hasBeenModifiedSinceMount: false
      };
    }),
    _React$useState2 = _slicedToArray(_React$useState, 2),
    dateState = _React$useState2[0],
    setDateState = _React$useState2[1];
  var _useValueWithTimezone = useValueWithTimezone({
      timezone: timezoneProp,
      value: inValue,
      defaultValue: defaultValue,
      onChange: onChange,
      valueManager: valueManager
    }),
    timezone = _useValueWithTimezone.timezone,
    handleValueChange = _useValueWithTimezone.handleValueChange;
  useValidation(_extends({}, props, {
    value: dateState.draft,
    timezone: timezone
  }), validator, valueManager.isSameError, valueManager.defaultErrorState);
  var updateDate = useEventCallback(function (action) {
    var updaterParams = {
      action: action,
      dateState: dateState,
      hasChanged: function hasChanged(comparison) {
        return !valueManager.areValuesEqual(utils, action.value, comparison);
      },
      isControlled: isControlled,
      closeOnSelect: closeOnSelect
    };
    var shouldPublish = shouldPublishValue(updaterParams);
    var shouldCommit = shouldCommitValue(updaterParams);
    var shouldClose = shouldClosePicker(updaterParams);
    setDateState(function (prev) {
      return _extends({}, prev, {
        draft: action.value,
        lastPublishedValue: shouldPublish ? action.value : prev.lastPublishedValue,
        lastCommittedValue: shouldCommit ? action.value : prev.lastCommittedValue,
        hasBeenModifiedSinceMount: true
      });
    });
    if (shouldPublish) {
      var validationError = action.name === 'setValueFromField' ? action.context.validationError : validator({
        adapter: adapter,
        value: action.value,
        props: _extends({}, props, {
          value: action.value,
          timezone: timezone
        })
      });
      var context = {
        validationError: validationError
      };

      // TODO v7: Remove 2nd condition
      if (action.name === 'setValueFromShortcut' && action.shortcut != null) {
        context.shortcut = action.shortcut;
      }
      handleValueChange(action.value, context);
    }
    if (shouldCommit && onAccept) {
      onAccept(action.value);
    }
    if (shouldClose) {
      setIsOpen(false);
    }
  });
  if (inValue !== undefined && (dateState.lastControlledValue === undefined || !valueManager.areValuesEqual(utils, dateState.lastControlledValue, inValue))) {
    var isUpdateComingFromPicker = valueManager.areValuesEqual(utils, dateState.draft, inValue);
    setDateState(function (prev) {
      return _extends({}, prev, {
        lastControlledValue: inValue
      }, isUpdateComingFromPicker ? {} : {
        lastCommittedValue: inValue,
        lastPublishedValue: inValue,
        draft: inValue,
        hasBeenModifiedSinceMount: true
      });
    });
  }
  var handleClear = useEventCallback(function () {
    updateDate({
      value: valueManager.emptyValue,
      name: 'setValueFromAction',
      pickerAction: 'clear'
    });
  });
  var handleAccept = useEventCallback(function () {
    updateDate({
      value: dateState.lastPublishedValue,
      name: 'setValueFromAction',
      pickerAction: 'accept'
    });
  });
  var handleDismiss = useEventCallback(function () {
    updateDate({
      value: dateState.lastPublishedValue,
      name: 'setValueFromAction',
      pickerAction: 'dismiss'
    });
  });
  var handleCancel = useEventCallback(function () {
    updateDate({
      value: dateState.lastCommittedValue,
      name: 'setValueFromAction',
      pickerAction: 'cancel'
    });
  });
  var handleSetToday = useEventCallback(function () {
    updateDate({
      value: valueManager.getTodayValue(utils, timezone, valueType),
      name: 'setValueFromAction',
      pickerAction: 'today'
    });
  });
  var handleOpen = useEventCallback(function () {
    return setIsOpen(true);
  });
  var handleClose = useEventCallback(function () {
    return setIsOpen(false);
  });
  var handleChange = useEventCallback(function (newValue) {
    var selectionState = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'partial';
    return updateDate({
      name: 'setValueFromView',
      value: newValue,
      selectionState: selectionState
    });
  });

  // TODO v7: Make changeImportance and label mandatory.
  var handleSelectShortcut = useEventCallback(function (newValue, changeImportance, shortcut) {
    return updateDate({
      name: 'setValueFromShortcut',
      value: newValue,
      changeImportance: changeImportance != null ? changeImportance : 'accept',
      shortcut: shortcut
    });
  });
  var handleChangeFromField = useEventCallback(function (newValue, context) {
    return updateDate({
      name: 'setValueFromField',
      value: newValue,
      context: context
    });
  });
  var handleFieldSelectedSectionsChange = useEventCallback(function (newSelectedSections) {
    setSelectedSections(newSelectedSections);
    onSelectedSectionsChange == null || onSelectedSectionsChange(newSelectedSections);
  });
  var actions = {
    onClear: handleClear,
    onAccept: handleAccept,
    onDismiss: handleDismiss,
    onCancel: handleCancel,
    onSetToday: handleSetToday,
    onOpen: handleOpen,
    onClose: handleClose
  };
  var fieldResponse = {
    value: dateState.draft,
    onChange: handleChangeFromField,
    selectedSections: selectedSections,
    onSelectedSectionsChange: handleFieldSelectedSectionsChange
  };
  var viewValue = React.useMemo(function () {
    return valueManager.cleanValue(utils, dateState.draft);
  }, [utils, valueManager, dateState.draft]);
  var viewResponse = {
    value: viewValue,
    onChange: handleChange,
    onClose: handleClose,
    open: isOpen,
    onSelectedSectionsChange: handleFieldSelectedSectionsChange
  };
  var isValid = function isValid(testedValue) {
    var error = validator({
      adapter: adapter,
      value: testedValue,
      props: _extends({}, props, {
        value: testedValue,
        timezone: timezone
      })
    });
    return !valueManager.hasError(error);
  };
  var layoutResponse = _extends({}, actions, {
    value: viewValue,
    onChange: handleChange,
    onSelectShortcut: handleSelectShortcut,
    isValid: isValid
  });
  return {
    open: isOpen,
    fieldProps: fieldResponse,
    viewProps: viewResponse,
    layoutProps: layoutResponse,
    actions: actions
  };
};