import { ApiError } from 'backend-api';
import { ProjectDetails } from 'backend-api/models';
import { useAppContext } from 'common-v2/hooks';
import { isRequestRestricted } from 'common-v2/transducers';
import { Form, Formik } from 'formik';
import { THEME, TOAST_TYPE, useManageToasts } from 'gdb-web-shared-components';
import { openPermissionErrorModal } from 'modals/permission-error-modal';
import { editProject } from 'project-v2/actions';
import { getFieldsWithDiffValues, getProjectFormValues } from 'project-v2/transducers';
import { ProjectFormValues } from 'project-v2/types';
import React, { useCallback, useMemo } from 'react';
import { useDispatch } from 'react-redux';

interface ProjectFormContainerProps {
  project?: ProjectDetails;
  onFinishEditing(): void;
  children: React.ReactNode;
}

export const ProjectFormContainer = React.memo(({ project, onFinishEditing, children }: ProjectFormContainerProps) => {
  const dispatch = useDispatch();
  const { user: userInfo, labels } = useAppContext();
  const { openToast } = useManageToasts(THEME.light);

  const initialValues = useMemo(() => getProjectFormValues(project?.id, project, userInfo, labels), [
    labels,
    project,
    userInfo,
  ]);

  const onSuccess = useCallback(
    (successMessage: React.ReactNode) => {
      onFinishEditing();

      openToast({
        id: 'edit-project-success',
        message: successMessage,
        type: TOAST_TYPE.SUCCESS,
      });
    },
    [onFinishEditing, openToast]
  );

  const onError = useCallback(
    (error: ApiError) => {
      if (isRequestRestricted(error)) {
        dispatch(openPermissionErrorModal(error));
        return;
      }

      openToast({
        id: 'edit-project-error',
        message: 'An error occurred while updating your Project data, please try again.',
        type: TOAST_TYPE.ERROR,
      });
    },
    [dispatch, openToast]
  );

  const onSubmit = useCallback(
    (data: ProjectFormValues) => {
      if (!project) {
        return;
      }

      const changedFields = getFieldsWithDiffValues(data, initialValues);

      dispatch(
        editProject.request({
          data,
          project,
          changedFields,
          onFinished: onFinishEditing,
          onSuccess,
          onError,
        })
      );
    },
    [project, initialValues, dispatch, onFinishEditing, onSuccess, onError]
  );

  return (
    <Formik initialValues={initialValues} onSubmit={onSubmit} enableReinitialize>
      <Form>{children}</Form>
    </Formik>
  );
});
