import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

import { Component, cloneElement, isValidElement, useRef, forwardRef, useImperativeHandle } from 'react';
import { getIn, setIn } from './utils';
import classNames from 'classnames';
import Measure from 'react-measure';
import { CLS_PREFIX } from '../../constants';
import Button from '../Button';
import { ButtonContext, getButtonContextValue } from '../Button/ButtonContext';
import FormField from '../FormField';
import Section from '../Section';
import Translate from '../Translate';
import FormContext from './FormContext';
import VerticalContext, { VERTICAL_BREAKPOINT } from '../VerticalContext';
import DisabledContext from './DisabledContext';
import { safeInvoke } from '../utils';
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
const actionButtonsConfig = getButtonContextValue({
  defaultProps: {
    size: 'lg'
  }
});
class Form extends Component {
  constructor() {
    var _this;
    super(...arguments);
    _this = this;
    _defineProperty(this, "state", {
      values: this.props.values,
      vertical: this.props.vertical || false,
      requiredFields: [],
      formContext: {
        getValues: () => this.state.values,
        getValue: (name, def) => {
          if (this.state.values) {
            return getIn(this.state.values, name, def);
          }
          return def;
        },
        setValue: (name, value) => {
          this.setState(_ref => {
            let {
              values
            } = _ref;
            if (values) {
              return {
                values: setIn(values, name, value)
              };
            }
            return null;
          });
          safeInvoke(this.props.onFieldChange, name, value);
        },
        getErrors: name => {
          if (this.props.errors) {
            return getIn(this.props.errors, name, {});
          }
          return {};
        },
        registerField: (name, field) => {
          if (name) {
            this.fields[name] = field;
          }
        },
        unregisterField: name => {
          if (name) {
            delete this.fields[name];
          }
        },
        setRequiredField: (name, required) => {
          this.setState(prevState => {
            if (required) {
              return {
                requiredFields: [...prevState.requiredFields, name]
              };
            }
            return {
              requiredFields: prevState.requiredFields.filter(v => v !== name)
            };
          });
        },
        getRequiredMark: () => this.props.requiredMark
      }
    });
    _defineProperty(this, "fields", {});
    _defineProperty(this, "handleSubmit", e => {
      e.preventDefault();
      if (this.props.onSubmit && this.state.values) {
        this.props.onSubmit(this.state.values, false);
      }
    });
    _defineProperty(this, "handleSubmitClick", e => {
      if (e.currentTarget.type === 'submit') {
        return;
      }
      if (this.props.onSubmit && this.state.values) {
        this.props.onSubmit(this.state.values, false);
      }
    });
    _defineProperty(this, "handleApplyClick", e => {
      if (e.currentTarget.type === 'submit') {
        return;
      }
      if (this.props.onSubmit && this.state.values) {
        this.props.onSubmit(this.state.values, true);
      }
    });
    _defineProperty(this, "handleResize", _ref2 => {
      let {
        bounds
      } = _ref2;
      const {
        vertical
      } = this.props;
      if (vertical !== undefined) {
        this.setState({
          vertical
        });
        return;
      }
      this.setState({
        vertical: bounds.width < VERTICAL_BREAKPOINT
      });
    });
    _defineProperty(this, "renderForm", function () {
      let {
        actionButtons
      } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
      const {
        innerRef,
        baseClassName,
        className,
        children,
        requiredMark,
        hideRequiredLegend,
        values,
        errors,
        submitButton,
        applyButton,
        cancelButton,
        onFieldChange,
        onSubmit,
        additionalButtons,
        footerClassName,
        state,
        render,
        vertical,
        ...props
      } = _this.props;
      return /*#__PURE__*/_jsx(FormContext.Provider, {
        value: _this.state.formContext,
        children: /*#__PURE__*/_jsx(VerticalContext.Provider, {
          value: _this.state.vertical,
          children: /*#__PURE__*/_jsx(DisabledContext.Provider, {
            value: !!state,
            children: /*#__PURE__*/_jsx(Measure, {
              onResize: _this.handleResize,
              innerRef: innerRef,
              bounds: true,
              children: _ref3 => {
                let {
                  measureRef
                } = _ref3;
                return /*#__PURE__*/_jsxs("form", {
                  ref: measureRef,
                  className: classNames(baseClassName, {
                    [`${baseClassName}--has-required`]: _this.hasRequiredField()
                  }, className),
                  onSubmit: _this.handleSubmit,
                  ...props,
                  children: [children, actionButtons, /*#__PURE__*/_jsx("input", {
                    type: "image",
                    src: "data:image/gif;base64,R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=",
                    style: {
                      border: 0,
                      height: 0,
                      width: 0,
                      position: 'absolute'
                    }
                  })]
                });
              }
            })
          })
        })
      });
    });
    _defineProperty(this, "renderActionButtons", () => {
      const {
        submitButton,
        applyButton,
        cancelButton,
        state,
        additionalButtons,
        baseClassName,
        footerClassName
      } = this.props;
      return /*#__PURE__*/_jsx(Section, {
        className: classNames(`${baseClassName}__footer`, footerClassName),
        children: /*#__PURE__*/_jsx(FormField, {
          children: /*#__PURE__*/_jsxs(ButtonContext.Provider, {
            value: actionButtonsConfig,
            children: [this.renderSubmitButton({
              submitButton,
              state
            }), this.renderApplyButton({
              applyButton,
              state
            }), this.renderAdditionalButtons({
              additionalButtons
            }), this.renderCancelButton({
              cancelButton,
              state
            })]
          })
        })
      });
    });
  }
  static getDerivedStateFromProps(props, state) {
    const {
      values,
      errors,
      requiredMark
    } = props;
    const {
      prevValues,
      prevErrors,
      prevRequiredMark
    } = state;
    const nextState = {};
    if (values !== prevValues) {
      nextState.values = values;
    }
    if (values !== prevValues || errors !== prevErrors || requiredMark !== prevRequiredMark) {
      nextState.formContext = {
        ...state.formContext
      };
    }
    nextState.prevValues = values;
    nextState.prevErrors = errors;
    nextState.prevRequiredMark = requiredMark;
    return nextState;
  }
  componentDidUpdate(prevProps) {
    const {
      errors
    } = this.props;
    if (errors !== prevProps.errors) {
      let field;
      let fieldErrors;
      Object.keys(this.fields).every(name => {
        const foundError = getIn(errors, name);
        if (foundError && typeof foundError === 'object' && Object.keys(foundError).length > 0) {
          field = this.fields[name];
          fieldErrors = foundError;
          return false;
        }
        return true;
      });
      if (field) {
        field.focus(fieldErrors);
      }
    }
  }
  hasRequiredField() {
    return this.props.requiredMark && this.state.requiredFields.length > 0;
  }
  renderSubmitButton(_ref4) {
    let {
      submitButton,
      state
    } = _ref4;
    if (!submitButton) {
      return null;
    }
    return /*#__PURE__*/_jsx(Button, {
      intent: "primary",
      state: state === 'submit' ? 'loading' : undefined,
      disabled: !!state,
      onClick: this.handleSubmitClick
      // eslint-disable-next-line react/no-children-prop
      ,
      children: /*#__PURE__*/_jsx(Translate, {
        content: "Form.submitButton",
        fallback: "Save"
      }),
      ...(typeof submitButton === 'object' ? submitButton : {})
    });
  }
  renderApplyButton(_ref5) {
    let {
      applyButton,
      state
    } = _ref5;
    if (!applyButton) {
      return null;
    }
    return /*#__PURE__*/_jsx(Button, {
      intent: "primary",
      state: state === 'apply' ? 'loading' : undefined,
      disabled: !!state,
      onClick: this.handleApplyClick
      // eslint-disable-next-line react/no-children-prop
      ,
      children: /*#__PURE__*/_jsx(Translate, {
        content: "Form.applyButton",
        fallback: "Apply"
      }),
      ...(typeof applyButton === 'object' ? applyButton : {})
    });
  }
  renderCancelButton(_ref6) {
    let {
      cancelButton,
      state
    } = _ref6;
    if (!cancelButton) {
      return null;
    }
    return /*#__PURE__*/_jsx(Button, {
      state: state === 'cancel' ? 'loading' : undefined,
      disabled: !!state
      // eslint-disable-next-line react/no-children-prop
      ,
      children: /*#__PURE__*/_jsx(Translate, {
        content: "Form.cancelButton",
        fallback: "Cancel"
      }),
      ...(typeof cancelButton === 'object' ? cancelButton : {})
    });
  }
  renderAdditionalButtons(_ref7) {
    let {
      additionalButtons
    } = _ref7;
    const {
      baseClassName
    } = this.props;
    if (Array.isArray(additionalButtons)) {
      return additionalButtons.map(element => {
        if ( /*#__PURE__*/isValidElement(element)) {
          const props = {
            className: classNames(element.props.className, `${baseClassName}__additional-button`)
          };
          return /*#__PURE__*/cloneElement(element, props);
        }
        return element;
      });
    }
    return null;
  }
  render() {
    const {
      render
    } = this.props;
    if (typeof render === 'function') {
      return render({
        renderForm: this.renderForm,
        renderActionButtons: this.renderActionButtons
      });
    }
    return this.renderForm({
      actionButtons: this.renderActionButtons()
    });
  }
}
_defineProperty(Form, "defaultProps", {
  children: undefined,
  requiredMark: /*#__PURE__*/_jsx("span", {
    className: `${CLS_PREFIX}form__required`
  }),
  hideRequiredLegend: false,
  values: {},
  errors: {},
  state: undefined,
  submitButton: true,
  applyButton: true,
  cancelButton: true,
  additionalButtons: [],
  onFieldChange: undefined,
  onSubmit: undefined,
  className: undefined,
  footerClassName: undefined,
  vertical: undefined,
  baseClassName: `${CLS_PREFIX}form`,
  render: undefined,
  innerRef: undefined
});
const RefForwardingForm = /*#__PURE__*/forwardRef((props, ref) => {
  const innerRef = useRef(null);
  useImperativeHandle(ref, () => ({
    submit() {
      innerRef.current?.dispatchEvent(new Event('submit', {
        cancelable: true,
        bubbles: true
      }));
    }
  }));
  return /*#__PURE__*/_jsx(Form, {
    innerRef: innerRef,
    ...props
  });
});
RefForwardingForm.displayName = 'Form';
/**
 * `Form` component is used for entering and submitting of user data.
 * [More details about designing of forms.](#!/Good%20Forms)
 * @since 0.0.54
 */
export default RefForwardingForm;