import "es6-promise/auto";
import { createStore } from "vuex";
import { fetchScopes } from "ChillMainAssets/lib/api/apiMethods.ts";
import { getAccompanyingCourse, getReferrersSuggested, getUsers } from "../api";
import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
import { datetimeToISO, ISOToDate } from "ChillMainAssets/chill/js/date";

const debug = process.env.NODE_ENV !== "production";
const id = window.accompanyingCourseId;

let getScopesPromise = (root) => {
  if (root === "app") {
    return fetchScopes();
  }
};
let accompanyingCoursePromise = getAccompanyingCourse(id);

let initPromise = (root) =>
  Promise.all([getScopesPromise(root), accompanyingCoursePromise]).then(
    ([scopes, accompanyingCourse]) =>
      new Promise((resolve) => {
        const store = createStore({
          strict: debug,
          modules: {},
          state: {
            accompanyingCourse: accompanyingCourse,
            addressContext: {},
            errorMsg: [],
            // all the available scopes
            scopes: scopes,
            // the scopes at start. If the user remove all scopes, we re-add those scopes, by security
            scopesAtStart: accompanyingCourse.scopes.map((scope) => scope),
            // the scope states at server side
            scopesAtBackend: accompanyingCourse.scopes.map((scope) => scope),
            // the users which are available for referrer
            referrersSuggested: [],
            // all the users available
            users: [],
            permissions: {},
            // controller for updating comment
            updateCommentAbortController: null,
            // waiting response for inserting first comment
            postFirstPinnedCommentResponse: null,
          },
          getters: {
            isPersonLocatingCourse: (state) => (person) => {
              if (state.accompanyingCourse.locationStatus !== "person") {
                return false;
              }

              return state.accompanyingCourse.personLocation.id === person.id;
            },
            isParticipationValid(state) {
              return state.accompanyingCourse.participations.length > 0;
            },
            isSocialIssueValid(state) {
              return state.accompanyingCourse.socialIssues.length > 0;
            },
            isOriginValid(state) {
              return state.accompanyingCourse.origin !== null;
            },
            isAdminLocationValid(state) {
              return state.accompanyingCourse.administrativeLocation !== null;
            },
            isLocationValid(state) {
              return state.accompanyingCourse.location !== null;
            },
            isJobValid(state) {
              return state.accompanyingCourse.job !== null;
            },
            isScopeValid(state) {
              //console.log('is scope valid', state.accompanyingCourse.scopes.length > 0);
              return state.accompanyingCourse.scopes.length > 0;
            },
            validationKeys(state, getters) {
              let keys = [];
              if (!getters.isParticipationValid) {
                keys.push("participation");
              }
              if (!getters.isLocationValid) {
                keys.push("location");
              }
              if (!getters.isJobValid) {
                keys.push("job");
              }
              if (!getters.isSocialIssueValid) {
                keys.push("socialIssue");
              }
              if (!getters.isOriginValid) {
                keys.push("origin");
              }
              if (!getters.isAdminLocationValid) {
                keys.push("adminLocation");
              }
              if (!getters.isScopeValid) {
                keys.push("scopes");
              }
              //console.log('getter keys', keys);
              return keys;
            },
            isValidToBeConfirmed(state, getters) {
              if (getters.validationKeys.length === 0) {
                return true;
              }
              return false;
            },
            canTogglePermission(state) {
              if (state.permissions.roles) {
                return state.permissions.roles[
                  "CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL"
                ];
              }

              return false;
            },
            usersFilteredByJob(state) {
              return state.users.filter((u) => {
                if (null !== state.accompanyingCourse.job) {
                  return (
                    (u.user_job === null ? null : u.user_job.id) ===
                    state.accompanyingCourse.job.id
                  );
                } else {
                  return true;
                }
              });
            },
            usersSuggestedFilteredByJob(state) {
              return state.referrersSuggested
                .filter((u) => {
                  if (null !== state.accompanyingCourse.job) {
                    return (
                      (u.user_job === null ? null : u.user_job.id) ===
                      state.accompanyingCourse.job.id
                    );
                  } else {
                    return true;
                  }
                })
                .filter((u) => {
                  if (null !== state.accompanyingCourse.user) {
                    return u.id !== state.accompanyingCourse.user.id;
                  }

                  return true;
                });
            },
          },
          mutations: {
            catchError(state, error) {
              // console.log('### mutation: a new error have been catched and pushed in store !', error);
              state.errorMsg.push(error);
            },
            removeParticipation(state, participation) {
              //console.log('### mutation: remove participation', participation.id);
              state.accompanyingCourse.participations =
                state.accompanyingCourse.participations.filter(
                  (element) => element !== participation,
                );
            },
            closeParticipation(state, { response, payload }) {
              //console.log('### mutation: close item', { participation, payload });
              // find row position and replace by closed participation
              state.accompanyingCourse.participations.splice(
                state.accompanyingCourse.participations.findIndex(
                  (element) => element === payload,
                ),
                1,
                response,
              );
            },
            addParticipation(state, participation) {
              //console.log('### mutation: add participation', participation);
              state.accompanyingCourse.participations.push(participation);
            },
            removeRequestor(state) {
              //console.log('### mutation: removeRequestor');
              state.accompanyingCourse.requestor = null;
            },
            addRequestor(state, requestor) {
              //console.log('### mutation: addRequestor', requestor);
              state.accompanyingCourse.requestor = requestor;
            },
            requestorIsAnonymous(state, value) {
              //console.log('### mutation: requestorIsAnonymous', value);
              state.accompanyingCourse.requestorAnonymous = value;
            },
            removeResource(state, resource) {
              //console.log('### mutation: removeResource', resource);
              state.accompanyingCourse.resources =
                state.accompanyingCourse.resources.filter(
                  (element) => element !== resource,
                );
            },
            addResource(state, resource) {
              //console.log('### mutation: addResource', resource);
              state.accompanyingCourse.resources.push(resource);
            },
            updateResource(state, payload) {
              console.log("### mutation: updateResource", payload);
              let i = state.accompanyingCourse.resources.findIndex(
                (r) => r.id === payload.id,
              );
              state.accompanyingCourse.resources[i] = payload;
            },
            updatePerson(state, payload) {
              console.log("### mutation: updatePerson", payload);
              let i = null;
              switch (payload.target) {
                case "participation":
                  i = state.accompanyingCourse.participations.findIndex(
                    (e) => e.person.id === payload.person.id,
                  );
                  state.accompanyingCourse.participations[i].person =
                    payload.person;
                  break;
                case "requestor":
                  state.accompanyingCourse.requestor = payload.person;
                  break;
                case "resource":
                  i = state.accompanyingCourse.resources.findIndex(
                    (e) => e.resource.id === payload.person.id,
                  );
                  state.accompanyingCourse.resources[i].resource =
                    payload.person;
                  break;
              }
            },
            updateThirdparty(state, payload) {
              console.log("### mutation: updateThirdparty", payload);
              let i = null;
              switch (payload.target) {
                case "requestor":
                  state.accompanyingCourse.requestor = payload.thirdparty;
                  break;
                case "resource":
                  i = state.accompanyingCourse.resources.findIndex(
                    (e) => e.resource.id === payload.thirdparty.id,
                  );
                  state.accompanyingCourse.resources[i].resource =
                    payload.thirdparty;
                  break;
              }
            },
            toggleIntensity(state, value) {
              state.accompanyingCourse.intensity = value;
            },
            toggleEmergency(state, value) {
              //console.log('### mutation: toggleEmergency');
              state.accompanyingCourse.emergency = value;
            },
            toggleConfidential(state, value) {
              //console.log('### mutation: toggleConfidential');
              state.accompanyingCourse.confidential = value;
            },
            setPinnedComment(state, content) {
              if (null === state.accompanyingCourse.pinnedComment) {
                state.accompanyingCourse.pinnedComment = {
                  id: -1,
                  content,
                  type: "accompanying_period_comment",
                };
              } else {
                state.accompanyingCourse.pinnedComment.content = content;
              }
            },
            setPinnedCommentDetails(state, value) {
              state.accompanyingCourse.pinnedComment.id = value.id;
              if (typeof value.creator !== "undefined") {
                state.accompanyingCourse.pinnedComment.creator = value.creator;
                state.accompanyingCourse.pinnedComment.updatedBy =
                  value.updatedBy;
                state.accompanyingCourse.pinnedComment.updatedAt =
                  value.updatedAt;
                state.accompanyingCourse.pinnedComment.createdAt =
                  value.createdAt;
              }
            },
            removePinnedComment(state) {
              state.accompanyingCourse.pinnedComment = null;
            },
            setPinCommentAbortController(state, value) {
              state.updateCommentAbortController = value;
            },
            setPostFirstPinnedCommentResponse(state, value) {
              state.postFirstPinnedCommentResponse = value;
            },
            updateSocialIssues(state, value) {
              console.log("updateSocialIssues", value);
              state.accompanyingCourse.socialIssues = value;
            },
            refreshSocialIssues(state, issues) {
              console.log("refreshSocialIssues", issues);
              state.accompanyingCourse.socialIssues = issues;
            },
            updateOrigin(state, value) {
              //console.log('value', value);
              state.accompanyingCourse.origin = value;
            },
            updateAdminLocation(state, value) {
              state.accompanyingCourse.administrativeLocation = value;
            },
            updateReferrer(state, value) {
              state.accompanyingCourse.user = value;
            },
            updateJob(state, value) {
              state.accompanyingCourse.job = value;
            },
            setReferrersSuggested(state, users) {
              state.referrersSuggested = users.map((u) => {
                if (state.accompanyingCourse.user !== null) {
                  if (state.accompanyingCourse.user.id === u.id) {
                    return state.accompanyingCourse.user;
                  }
                }
                return u;
              });
            },
            confirmAccompanyingCourse(state, response) {
              //console.log('### mutation: confirmAccompanyingCourse: response', response);
              state.accompanyingCourse.step = response.step;
            },
            setAddressContext(state, context) {
              //console.log('define location context');
              state.addressContext = context;
            },
            setUsers(state, users) {
              state.users = users.map((u) => {
                if (state.accompanyingCourse.user !== null) {
                  if (state.accompanyingCourse.user.id === u.id) {
                    return state.accompanyingCourse.user;
                  }
                }
                return u;
              });
            },
            setPermissions(state, permissions) {
              state.permissions = permissions;
              // console.log('permissions', state.permissions);
            },
            updateLocation(state, r) {
              //console.log('### mutation: set location attributes', r);
              state.accompanyingCourse.locationStatus = r.locationStatus;
              if (r.locationStatus !== "person") {
                state.addressContext.addressId = r.location.address_id;
                //console.log('mutation: update context addressId', state.addressContext.addressId);
              }
              state.accompanyingCourse.location = r.location;
              state.accompanyingCourse.personLocation = r.personLocation;
            },
            setEditContextTrue(state, payload) {
              //console.log('### mutation: set edit context true with addressId', payload.addressId);
              state.addressContext.edit = true;
              state.addressContext.addressId = payload.addressId;
            },
            setScopes(state, scopes) {
              state.accompanyingCourse.scopes = scopes;
            },
            addScopeAtBackend(state, scope) {
              let scopeIds = state.scopesAtBackend.map((s) => s.id);
              if (!scopeIds.includes(scope.id)) {
                state.scopesAtBackend.push(scope);
              }
            },
            removeScopeAtBackend(state, scope) {
              let scopeIds = state.scopesAtBackend.map((s) => s.id);
              if (scopeIds.includes(scope.id)) {
                state.scopesAtBackend = state.scopesAtBackend.filter(
                  (s) => s.id !== scope.id,
                );
              }
            },
            updateStartDate(state, date) {
              state.accompanyingCourse.openingDate = date;
            },
          },
          actions: {
            //QUESTION: does this serve a purpose? Participations can be closed...
            removeParticipation({ commit }, payload) {
              commit("removeParticipation", payload);
              // fetch DELETE request...
            },
            addPerson({ commit }, payload) {
              commit("updatePerson", {
                target: payload.target,
                person: payload.body,
              });
            },
            addThirdparty({ commit }, payload) {
              commit("updateThirdparty", {
                target: payload.target,
                thirdparty: payload.body,
              });
            },
            /**
             * Add/close participation
             */
            closeParticipation({ commit }, payload) {
              const body = { type: payload.person.type, id: payload.person.id };
              const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;

              return makeFetch("DELETE", url, body)
                .then((response) => {
                  commit("closeParticipation", { response, payload });
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            addParticipation({ commit }, payload) {
              const body = { type: payload.result.type, id: payload.result.id };
              const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;

              return makeFetch("POST", url, body)
                .then((response) => {
                  commit("addParticipation", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            /**
             * Add/remove pinnedComment
             */
            removePinnedComment({ commit }, payload) {
              const body = {
                type: "accompanying_period_comment",
                id: payload.id,
              };
              const url = `/api/1.0/person/accompanying-course/${id}/comment.json`;

              return makeFetch("DELETE", url, body)
                .then(() => {
                  commit("removePinnedComment");
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            /**
             * internal method to insert a new comment
             *
             * @param commit
             * @param dispatch
             * @param content
             * @returns {*}
             */
            addPinnedComment({ commit, dispatch }, content) {
              const url = `/api/1.0/person/accompanying-course/${id}/comment.json`;

              return makeFetch("POST", url, {
                type: "accompanying_period_comment",
                content,
              })
                .then((response) => {
                  commit("setPinnedCommentDetails", response);
                  return dispatch("patchFirstComment", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updatePinnedComment({ commit, state, dispatch }, content) {
              commit("setPinnedComment", content);
              if (
                state.accompanyingCourse.pinnedComment.id === -1 &&
                state.postFirstPinnedCommentResponse === null
              ) {
                let r = dispatch("addPinnedComment", content).then(() => {
                  commit("setPostFirstPinnedCommentResponse", null);
                });
                commit("setPostFirstPinnedCommentResponse", r);
              } else {
                (state.postFirstPinnedCommentResponse === null
                  ? Promise.resolve()
                  : state.postFirstPinnedCommentResponse
                ).then(() => {
                  dispatch("updateExistingPinnedComment", content);
                });
              }
            },
            /**
             * internal method to patch an existing comment
             *
             * @param commit
             * @param state
             * @param comment
             * @returns {*}
             */
            updateExistingPinnedComment({ commit, state }, content) {
              const payload = {
                type: "accompanying_period_comment",
                content,
                id: state.accompanyingCourse.pinnedComment.id,
              };
              const url = `/api/1.0/person/accompanying-period/comment/${payload.id}.json`;

              if (state.updateCommentAbortController !== null) {
                state.updateCommentAbortController.abort();
                commit("setPinCommentAbortController", null);
              }

              let controller = new AbortController();
              commit("setPinCommentAbortController", controller);

              return makeFetch("PATCH", url, payload, {
                signal: controller.signal,
              })
                .then((response) => {
                  commit("setPinCommentAbortController", null);
                  commit("setPinnedCommentDetails", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  commit("setPinCommentAbortController", null);
                  throw error;
                });
            },
            /**
             * Add/remove/display anonymous requestor
             */
            removeRequestor({ commit, dispatch }) {
              const body = {};
              const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;

              return makeFetch("DELETE", url, body)
                .then(() => {
                  commit("removeRequestor");
                  dispatch("requestorIsAnonymous", false);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            addRequestor({ commit }, payload) {
              const body = payload
                ? { type: payload.result.type, id: payload.result.id }
                : {};
              const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;

              return makeFetch("POST", url, body)
                .then((response) => {
                  commit("addRequestor", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            requestorIsAnonymous({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const body = {
                type: "accompanying_period",
                requestorAnonymous: payload,
              };

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("requestorIsAnonymous", response.requestorAnonymous);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            /**
             * Add/remove resource
             */
            removeResource({ commit }, payload) {
              const body = { type: "accompanying_period_resource" };
              body["id"] = payload.id;
              const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;

              return makeFetch("DELETE", url, body)
                .then(() => {
                  commit("removeResource", payload);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            addResource({ commit }, payload) {
              const body = { type: "accompanying_period_resource" };
              body["resource"] = {
                type: payload.result.type,
                id: payload.result.id,
              };
              const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;

              return makeFetch("POST", url, body)
                .then((response) => {
                  commit("addResource", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            patchResource({ commit }, payload) {
              const body = { type: "accompanying_period_resource" };
              body["resource"] = {
                type: payload.result.type,
                id: payload.result.id,
              };
              const url = `/api/1.0/person/accompanying-course/resource/${id}.json`;

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("patchResource", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            /**
             * Update accompanying course intensity/emergency/confidentiality
             */
            toggleIntensity({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}/intensity.json`;
              const body = { type: "accompanying_period", intensity: payload };

              return makeFetch("POST", url, body)
                .then((response) => {
                  commit("toggleIntensity", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            toggleEmergency({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const body = { type: "accompanying_period", emergency: payload };

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("toggleEmergency", response.emergency);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            toggleConfidential({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}/confidential.json`;
              const body = {
                type: "accompanying_period",
                confidential: payload,
              };

              console.log("url", url, "body", body);

              return makeFetch("POST", url, body)
                .then((response) => {
                  console.log("response", response);
                  commit("toggleConfidential", response);
                })
                .catch((error) => {
                  console.log("error", error);
                  commit("catchError", error);
                  throw error;
                });
            },
            /**
             * Handle the checked/unchecked scopes
             *
             * When the user set the scopes in a invalid situation (when no scopes are cheched), this
             * method will internally re-add the scopes as they were originally when the page was loaded, but
             * this does not appears for the user (they remains unchecked). When the user re-add a scope, the
             * scope is back in a valid state, and the store synchronize with the new state (all the original scopes
             * are removed if necessary, and the new checked scopes is backed).
             *
             * So, for instance:
             *
             * at load:
             *
             * [x] scope A (at backend: [x])
             * [x] scope B (at backend: [x])
             * [ ] scope C (at backend: [ ])
             *
             * The user uncheck scope A:
             *
             * [ ] scope A (at backend: [ ] as soon as the operation finish)
             * [x] scope B (at backend: [x])
             * [ ] scope C (at backend: [ ])
             *
             * The user uncheck scope B. The state is invalid (no scope checked), so we go back to initial state when
             * the page loaded):
             *
             * [ ] scope A (at backend: [x] as soon as the operation finish)
             * [ ] scope B (at backend: [x] as soon as the operation finish)
             * [ ] scope C (at backend: [ ])
             *
             * The user check scope C. The scopes are back to valid state. So we go back to synchronization with UI and
             * backend):
             *
             * [ ] scope A (at backend: [ ] as soon as the operation finish)
             * [ ] scope B (at backend: [ ] as soon as the operation finish)
             * [x] scope C (at backend: [x] as soon as the operation finish)
             *
             * **Warning** There is a problem if the user check/uncheck faster than the backend is synchronized.
             *
             * @param commit
             * @param state
             * @param dispatch
             * @param scopes
             * @returns Promise
             */
            setScopes({ commit, state, dispatch }, scopes) {
              let currentServerScopesIds = state.scopesAtBackend.map(
                (scope) => scope.id,
              );
              let checkedScopesIds = scopes.map((scope) => scope.id);
              let removedScopesIds = currentServerScopesIds.filter(
                (id) => !checkedScopesIds.includes(id),
              );
              let addedScopesIds = checkedScopesIds.filter(
                (id) => !currentServerScopesIds.includes(id),
              );

              return dispatch("updateScopes", {
                addedScopesIds,
                removedScopesIds,
              })
                .catch((error) => {
                  throw error;
                })
                .then(() => {
                  // warning: when the operation of dispatch are too slow, the user may check / uncheck before
                  // the end of the synchronisation with the server (done by dispatch operation). Then, it leads to
                  // check/uncheck in the UI. I do not know of to avoid it.
                  commit("setScopes", scopes);
                  return Promise.resolve();
                })
                .then(() => {
                  return dispatch("fetchReferrersSuggested");
                });
              /*
               else {
                  return dispatch('setScopes', state.scopesAtStart).then(() => {
                     commit('setScopes', scopes);
                     return Promise.resolve();
                  }).then(() => {
                     return dispatch('fetchReferrersSuggested');
                  });
               }
                */
            },
            /**
             * Internal function for the store to effectively update scopes.
             *
             * Return a promise which resolves when all update operation are
             * successful and finished.
             *
             * @param state
             * @param commit
             * @param addedScopesIds
             * @param removedScopesIds
             * @return Promise
             */
            updateScopes(
              { state, commit },
              { addedScopesIds, removedScopesIds },
            ) {
              let promises = [];
              const url = `/api/1.0/person/accompanying-course/${state.accompanyingCourse.id}/scope.json`;
              state.scopes.forEach((scope) => {
                const body = {
                  id: scope.id,
                  type: scope.type,
                };

                if (addedScopesIds.includes(scope.id)) {
                  promises.push(
                    makeFetch("POST", url, body)
                      .then((response) => {
                        commit("addScopeAtBackend", scope);
                        return response;
                      })
                      .catch((error) => {
                        commit("catchError", error);
                        throw error;
                      }),
                  );
                }
                if (removedScopesIds.includes(scope.id)) {
                  promises.push(
                    makeFetch("DELETE", url, body)
                      .then((response) => {
                        commit("removeScopeAtBackend", scope);
                        return response;
                      })
                      .catch((error) => {
                        commit("catchError", error);
                        throw error;
                      }),
                  );
                }
              });

              return Promise.all(promises);
            },
            patchFirstComment({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const body = {
                type: "accompanying_period",
                pinnedComment: {
                  type: "accompanying_period_comment",
                  id: payload.id,
                },
              };
              return makeFetch("PATCH", url, body).catch((error) => {
                commit("catchError", error);
                throw error;
              });
            },
            updateSocialIssues(
              { state, commit, dispatch },
              { payload, body, method },
            ) {
              const url = `/api/1.0/person/accompanying-course/${id}/socialissue.json`;
              return makeFetch(method, url, body)
                .then(() => {
                  commit("updateSocialIssues", payload);
                })
                .then(() => {
                  return getAccompanyingCourse(state.accompanyingCourse.id);
                })
                .then((accompanying_course) => {
                  commit(
                    "refreshSocialIssues",
                    accompanying_course.socialIssues,
                  );
                  dispatch("fetchReferrersSuggested");
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateOrigin({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const body = {
                type: "accompanying_period",
                origin: { id: payload.id, type: payload.type },
              };

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("updateOrigin", response.origin);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateAdminLocation({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const body = {
                type: "accompanying_period",
                administrativeLocation: { id: payload.id, type: payload.type },
              };

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit(
                    "updateAdminLocation",
                    response.administrativeLocation,
                  );
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateReferrer({ commit, state }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              let body = { type: "accompanying_period", user: null };

              if (payload !== null) {
                body = {
                  type: "accompanying_period",
                  user: { id: payload.id, type: payload.type },
                };
              }

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("updateReferrer", response.user);
                  if (
                    null !== payload &&
                    null !== payload.user_job &&
                    payload.user_job !== state.accompanyingCourse.job
                  ) {
                    this.dispatch("updateJob", payload.user_job);
                  }
                  // commit('setFilteredReferrersSuggested'); // this mutation doesn't exist?
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateJob({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              let body = { type: "accompanying_period", job: null };

              console.log("update job", payload);

              if (payload !== null) {
                body = {
                  type: "accompanying_period",
                  job: { id: payload.id, type: payload.type },
                };
              }

              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("updateJob", response.job);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateStartDate({ commit }, payload) {
              const url = `/api/1.0/person/accompanying-course/${id}.json`;
              const date =
                payload === null || payload === ""
                  ? null
                  : { datetime: datetimeToISO(ISOToDate(payload)) };
              const body = { type: "accompanying_period", openingDate: date };
              return makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("updateStartDate", response.openingDate);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            async fetchReferrersSuggested({ state, commit }) {
              let users = await getReferrersSuggested(state.accompanyingCourse);
              commit("setReferrersSuggested", users);
              if (
                null === state.accompanyingCourse.user &&
                !state.accompanyingCourse.confidential &&
                !state.accompanyingCourse.step === "DRAFT" &&
                users.length === 1
              ) {
                // set the user if unique
                commit("updateReferrer", users[0]);
              }
            },
            async fetchUsers({ commit }) {
              let users = await getUsers();
              commit("setUsers", users);
            },
            /**
             * By adding more roles to body['roles'], more permissions can be checked.
             */
            fetchPermissions({ commit }) {
              const url = "/api/1.0/main/permissions/info.json";
              const body = {
                object: {
                  type: "accompanying_period",
                  id: id,
                },
                class: "Chill\\PersonBundle\\Entity\\AccompanyingPeriod",
                roles: ["CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL"],
              };

              return makeFetch("POST", url, body)
                .then((response) => {
                  commit("setPermissions", response);

                  return Promise.resolve();
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            updateLocation({ commit, dispatch }, payload) {
              //console.log('## action: updateLocation', payload.locationStatusTo);
              const url = `/api/1.0/person/accompanying-course/${payload.targetId}.json`;
              let body = { type: payload.target, id: payload.targetId };
              let location = {};
              if (payload.locationStatusTo === "person") {
                // patch for person address (don't remove addressLocation)
                location = {
                  personLocation: { type: "person", id: payload.personId },
                };
              } else if (payload.locationStatusTo === "address") {
                // patch for temporary address
                location = {
                  personLocation: null,
                  addressLocation: { id: payload.addressId },
                };
              } else {
                // patch to remove person address
                location = { personLocation: null };
              }
              Object.assign(body, location);
              makeFetch("PATCH", url, body)
                .then((response) => {
                  commit("updateLocation", {
                    location: response.location,
                    locationStatus: response.locationStatus,
                    personLocation: response.personLocation,
                  });
                  dispatch("fetchReferrersSuggested");
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
            confirmAccompanyingCourse({ commit }) {
              const url = `/api/1.0/person/accompanying-course/${id}/confirm.json`;
              makeFetch("POST", url)
                .then((response) => {
                  window.location.replace(`/fr/parcours/${id}`);
                  commit("confirmAccompanyingCourse", response);
                })
                .catch((error) => {
                  commit("catchError", error);
                  throw error;
                });
            },
          },
        });

        if (root === "app") {
          store.dispatch("fetchReferrersSuggested");
          store.dispatch("fetchUsers");
        }

        resolve(store);
      }),
  );

export { initPromise };
