function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

import * as React from 'react';
import { createUseStyles } from '@fluent-ui/styles';
import { styles } from './Form.styled';
import { FormPropTypes } from './Form.type';
import Field from './components/Field';
import { FormContext } from './Form.context';
import { createValidator } from './Form.validator';
import classNames from 'classnames';
export const name = 'Form';
const useStyles = createUseStyles(styles, {
  name
});
const Form = React.forwardRef((props, ref) => {
  const {
    className: classNameProp,
    children,
    prefix,
    suffix,
    initialState,
    onSubmit,
    ...rest
  } = props;
  const childrenArray = React.useMemo(() => React.Children.toArray(children).map(child => !!child.props.rules && child).filter(v => v), [children]);
  const fields = React.useMemo(() => initialState || childrenArray.reduce((acc, cur) => ({ ...acc,
    [cur.props.name]: ''
  }), {}), [childrenArray, initialState]);
  const reducer = React.useCallback((state, action) => {
    switch (action.type) {
      case 'reset':
        return {
          values: fields,
          errors: {}
        };

      case 'onChange':
        return {
          values: { ...state.values,
            ...action.payload
          },
          errors: state.errors
        };

      case 'onError':
        // eslint-disable-next-line
        const errors = Array.isArray(action.payload) ? action.payload.reduce((acc, cur) => ({ ...acc,
          [cur.field]: cur.message
        }), {}) : {};
        return {
          values: state.values,
          errors
        };

      default:
        throw new Error('The `type` provided by `dispatch` does not conform to the specification');
    }
  }, [fields]);
  const [state, dispatch] = React.useReducer(reducer, {
    values: fields,
    errors: {}
  });
  const descriptor = React.useMemo(() => childrenArray.reduce((acc, cur) => ({ ...acc,
    [cur.props.name]: cur.props.rules
  }), {}), [childrenArray]);
  const contextValue = {
    state,
    dispatch,
    descriptor
  }; // Used to control the content triggered by the submit event

  const handleSubmit = React.useCallback(e => {
    e.preventDefault();
    createValidator(descriptor, state.values, errors => {
      dispatch({
        type: 'onError',
        payload: errors
      });
      onSubmit && onSubmit(state.values, errors);
    });
  }, [state, onSubmit, descriptor]);
  const classes = useStyles(props);
  const className = classNames(classes.root, classNameProp);
  return React.createElement("form", _extends({
    className: className,
    ref: ref,
    onSubmit: handleSubmit
  }, rest), React.createElement(FormContext.Provider, {
    value: contextValue
  }, React.createElement("table", {
    className: classes.table
  }, React.createElement("caption", null, prefix), React.createElement("tbody", null, React.Children.map(children, child => child), React.createElement("tr", null, React.createElement("td", {
    colSpan: 2
  }, suffix))))));
});
Object.defineProperty(Form, 'Field', {
  get() {
    return Field;
  }

});
Form.displayName = `F${name}`;
Form.propTypes = FormPropTypes;
export default Form;