import { addIdToValue, removeIdFromValue } from "./utils";
import {
  fetchCalendarRangeForUser,
  fetchCalendarRemoteForUser,
  fetchCalendarLocalForUser,
} from "./../api";
import { datetimeToISO } from "ChillMainAssets/chill/js/date";
import { postLocation } from "ChillActivityAssets/vuejs/Activity/api";

/**
 * This will store a unique key for each value, and prevent to launch the same
 * request multiple times, when fetching user calendars.
 *
 * Actually, each time a user is added or removed, the methods "dateSet" is executed and this
 * sparkle a request by user to get the calendar data. When the calendar data is fetched, it is
 * immediatly added to the calendar which, in turn , launch the event dateSet and re-launch fetch
 * queries which has not yet ended. Storing the queries already executed prevent this loop.
 *
 * @type {Set<String>}
 */
const fetchings = new Set();

export default {
  setCurrentDatesView({ commit, dispatch }, { start, end }) {
    commit("setCurrentDatesView", { start, end });

    return dispatch("fetchCalendarEvents");
  },
  fetchCalendarEvents({ state, getters, dispatch }) {
    if (state.currentView.start === null && state.currentView.end === null) {
      return Promise.resolve();
    }

    let promises = [];
    for (const uid of state.currentView.users.keys()) {
      let unique = `${uid}, ${state.currentView.start.toISOString()}, ${state.currentView.end.toISOString()}`;

      if (fetchings.has(unique)) {
        console.log("prevent from fetching for a user", unique);
        continue;
      }

      fetchings.add(unique);

      promises.push(
        dispatch("fetchCalendarRangeForUser", {
          user: state.usersData.get(uid).user,
          start: state.currentView.start,
          end: state.currentView.end,
        }),
      );
      promises.push(
        dispatch("fetchCalendarRemotesForUser", {
          user: state.usersData.get(uid).user,
          start: state.currentView.start,
          end: state.currentView.end,
        }),
      );
      promises.push(
        dispatch("fetchCalendarLocalsForUser", {
          user: state.usersData.get(uid).user,
          start: state.currentView.start,
          end: state.currentView.end,
        }),
      );
    }

    return Promise.all(promises);
  },
  fetchCalendarRangeForUser({ commit, getters }, { user, start, end }) {
    if (!getters.isCalendarRangeLoadedForUser({ user, start, end })) {
      return fetchCalendarRangeForUser(user, start, end).then((ranges) => {
        commit("addCalendarRangesForUser", { user, ranges, start, end });

        return Promise.resolve();
      });
    }
  },
  fetchCalendarRemotesForUser({ commit, getters }, { user, start, end }) {
    if (!getters.isCalendarRemoteLoadedForUser({ user, start, end })) {
      return fetchCalendarRemoteForUser(user, start, end).then((remotes) => {
        commit("addCalendarRemotesForUser", { user, remotes, start, end });

        return Promise.resolve();
      });
    }
  },
  fetchCalendarLocalsForUser({ commit, getters }, { user, start, end }) {
    if (!getters.isCalendarRemoteLoadedForUser({ user, start, end })) {
      return fetchCalendarLocalForUser(user, start, end).then((locals) => {
        commit("addCalendarLocalsForUser", { user, locals, start, end });

        return Promise.resolve();
      });
    }
  },
  addPersonsInvolved({ commit, dispatch }, payload) {
    console.log("### action addPersonsInvolved", payload.result.type);
    console.log("### action addPersonsInvolved payload result", payload.result);
    switch (payload.result.type) {
      case "person":
        let aPersons = document.getElementById(
          "chill_activitybundle_activity_persons",
        );
        aPersons.value = addIdToValue(aPersons.value, payload.result.id);
        break;
      case "thirdparty":
        let aThirdParties = document.getElementById(
          "chill_activitybundle_activity_professionals",
        );
        aThirdParties.value = addIdToValue(
          aThirdParties.value,
          payload.result.id,
        );
        break;
      case "user":
        let aUsers = document.getElementById(
          "chill_activitybundle_activity_users",
        );
        aUsers.value = addIdToValue(aUsers.value, payload.result.id);
        commit("showUserOnCalendar", {
          user: payload.result,
          ranges: false,
          remotes: true,
        });
        dispatch("fetchCalendarEvents");
        break;
    }
    commit("addPersonsInvolved", payload);
  },
  removePersonInvolved({ commit }, payload) {
    //console.log('### action removePersonInvolved', payload);
    switch (payload.type) {
      case "person":
        let aPersons = document.getElementById(
          "chill_activitybundle_activity_persons",
        );
        aPersons.value = removeIdFromValue(aPersons.value, payload.id);
        break;
      case "thirdparty":
        let aThirdParties = document.getElementById(
          "chill_activitybundle_activity_professionals",
        );
        aThirdParties.value = removeIdFromValue(
          aThirdParties.value,
          payload.id,
        );
        break;
      case "user":
        let aUsers = document.getElementById(
          "chill_activitybundle_activity_users",
        );
        aUsers.value = removeIdFromValue(aUsers.value, payload.id);
        break;
    }
    commit("removePersonInvolved", payload);
  },

  // Calendar
  /**
   * set event startDate and endDate.
   *
   * if the mainUser is different from "me", it will replace the mainUser
   *
   * @param commit
   * @param state
   * @param getters
   * @param start
   * @param end
   */
  setEventTimes({ commit, state, getters }, { start, end }) {
    console.log("### action createEvent", { start, end });
    let startDateInput = document.getElementById(
      "chill_activitybundle_activity_startDate",
    );
    startDateInput.value = null !== start ? datetimeToISO(start) : "";
    let endDateInput = document.getElementById(
      "chill_activitybundle_activity_endDate",
    );
    endDateInput.value = null !== end ? datetimeToISO(end) : "";
    let calendarRangeInput = document.getElementById(
      "chill_activitybundle_activity_calendarRange",
    );
    calendarRangeInput.value = "";

    if (
      getters.getMainUser === null ||
      getters.getMainUser.id !== state.me.id
    ) {
      let mainUserInput = document.getElementById(
        "chill_activitybundle_activity_mainUser",
      );
      mainUserInput.value = state.me.id;
      commit("setMainUser", state.me);
    }

    commit("setEventTimes", { start, end });
  },
  associateCalendarToRange({ state, commit, dispatch, getters }, { range }) {
    console.log("### action associateCAlendarToRange", range);
    let startDateInput = document.getElementById(
      "chill_activitybundle_activity_startDate",
    );
    startDateInput.value = null !== range ? datetimeToISO(range.start) : "";
    let endDateInput = document.getElementById(
      "chill_activitybundle_activity_endDate",
    );
    endDateInput.value = null !== range ? datetimeToISO(range.end) : "";
    let calendarRangeInput = document.getElementById(
      "chill_activitybundle_activity_calendarRange",
    );
    calendarRangeInput.value =
      null !== range ? Number(range.extendedProps.calendarRangeId) : "";

    if (null !== range) {
      let location = getters.getLocationById(range.extendedProps.locationId);

      if (null === location) {
        console.error("location not found!", range.extendedProps.locationId);
      }

      dispatch("updateLocation", location);

      const userId = range.extendedProps.userId;
      if (
        state.activity.mainUser !== null &&
        state.activity.mainUser.id !== userId
      ) {
        dispatch("setMainUser", state.usersData.get(userId).user);

        // TODO: remove persons involved with this user
      }
    }

    commit("associateCalendarToRange", { range });
    return Promise.resolve();
  },
  setMainUser({ commit, dispatch, state }, mainUser) {
    console.log("setMainUser", mainUser);

    let mainUserInput = document.getElementById(
      "chill_activitybundle_activity_mainUser",
    );
    mainUserInput.value = Number(mainUser.id);

    return dispatch("associateCalendarToRange", { range: null }).then(() => {
      commit("setMainUser", mainUser);

      return dispatch("fetchCalendarEvents");
    });
  },

  // Location
  updateLocation({ commit }, value) {
    console.log("### action: updateLocation", value);
    let hiddenLocation = document.getElementById(
      "chill_activitybundle_activity_location",
    );
    if (value.onthefly) {
      const body = {
        type: "location",
        name:
          value.name === "__AccompanyingCourseLocation__" ? null : value.name,
        locationType: {
          id: value.locationType.id,
          type: "location-type",
        },
      };
      if (value.address.id) {
        Object.assign(body, {
          address: {
            id: value.address.id,
          },
        });
      }
      postLocation(body)
        .then((location) => (hiddenLocation.value = location.id))
        .catch((err) => {
          console.log(err.message);
        });
    } else {
      hiddenLocation.value = value.id;
    }
    commit("updateLocation", value);
  },
};
