import { createStore } from "vuex";
import {
  householdMove,
  fetchHouseholdSuggestionByAccompanyingPeriod,
  fetchAddressSuggestionByPerson,
} from "./../api.js";
import { fetchResults } from "ChillMainAssets/lib/api/apiMethods.ts";
import { fetchHouseholdByAddressReference } from "ChillPersonAssets/lib/household.js";
import {
  datetimeToISO,
  dateToISO,
  ISOToDate,
} from "ChillMainAssets/chill/js/date";

const debug = process.env.NODE_ENV !== "production";
//console.log('AJAJAJA', window.addaddress);

const concerned = window.household_members_editor_data.persons.map((p) => {
  return {
    person: p,
    position: null,
    allowRemove: false,
    holder: false,
    comment: "",
  };
});

const store = createStore({
  strict: debug,
  state: {
    concerned,
    household: window.household_members_editor_data.household,
    positions: window.household_members_editor_data.positions.sort((a, b) => {
      if (a.ordering < b.ordering) {
        return -1;
      }
      if (a.ordering > b.ordering) {
        return 1;
      }
      return 0;
    }),
    startDate: dateToISO(new Date()),
    /**
     * Indicates if the destination is:
     *
     * * "new" => a new household
     * * "existing" => an existing household
     * * "leave" => leave without household
     * * null if not set
     */
    mode:
      window.household_members_editor_data.household === null
        ? null
        : "existing",
    allowHouseholdCreate:
      window.household_members_editor_data.allowHouseholdCreate,
    allowHouseholdSearch:
      window.household_members_editor_data.allowHouseholdSearch,
    allowLeaveWithoutHousehold:
      window.household_members_editor_data.allowLeaveWithoutHousehold,
    forceLeaveWithoutHousehold: false,
    /**
     * If true, the user explicitly said that no address is possible
     */
    forceHouseholdNoAddress: false,
    /**
     * Household suggestions
     *
     * (this is not restricted to "suggestion by accompanying periods")
     */
    householdSuggestionByAccompanyingPeriod: [], // TODO rename into householdsSuggestion
    showHouseholdSuggestion:
      window.household_members_editor_expand_suggestions === 1,
    householdCompositionType: null,
    numberOfChildren: 0,
    numberOfDependents: 0,
    numberOfDependentsWithDisabilities: 0,
    addressesSuggestion: [],
    showAddressSuggestion: true,
    householdCompositionTypes: [],
    warnings: [],
    errors: [],
  },
  getters: {
    /**
     * return true if this page allow to create a new household
     *
     * @returns {boolean}
     */
    isModeNewAllowed(state) {
      return state.allowHouseholdCreate;
    },
    /**
     * return true if this page allow to "leave without household"
     *
     * @returns {boolean}
     */
    isModeLeaveAllowed(state) {
      return state.allowLeaveWithoutHousehold;
    },
    /**
     * return true if the mode "leave" is selected
     *
     * @returns {boolean}
     */
    isModeLeave(state) {
      return state.mode === "leave";
    },
    isHouseholdForceNoAddress(state) {
      return state.forceHouseholdNoAddress;
    },
    getSuggestions(state) {
      let suggestions = [];
      state.householdSuggestionByAccompanyingPeriod.forEach((h) => {
        suggestions.push({ household: h });
      });

      return suggestions;
    },
    isHouseholdNew(state) {
      return state.mode === "new";
    },
    getAddressContext(state, getters) {
      if (state.household === null) {
        return {};
      }

      if (!getters.hasHouseholdAddress) {
        return {
          edit: false,
          addressId: null,
          target: {
            name: state.household.type,
            id: state.household.id,
          },
          defaults: window.addaddress,
          suggestions: state.addressesSuggestion,
        };
      } else {
        return {
          edit: true,
          addressId: state.household.current_address.id,
          target: {
            name: state.household.type,
            id: state.household.id,
          },
          defaults: window.addaddress,
        };
      }
    },
    hasHouseholdAddress(state) {
      if (null === state.household) {
        return false;
      }
      return state.household.current_address !== null;
    },
    hasHousehold(state) {
      return state.household !== null;
    },
    hasHouseholdOrLeave(state) {
      return state.household !== null || state.forceLeaveWithoutHousehold;
    },
    hasHouseholdSuggestion(state, getters) {
      return getters.filterHouseholdSuggestionByAccompanyingPeriod.length > 0;
    },
    countHouseholdSuggestion(state, getters) {
      return getters.filterHouseholdSuggestionByAccompanyingPeriod.length;
    },
    filterHouseholdSuggestionByAccompanyingPeriod(state) {
      if (state.household === null) {
        return state.householdSuggestionByAccompanyingPeriod;
      }

      return state.householdSuggestionByAccompanyingPeriod.filter(
        (h) => h.id !== state.household.id,
      );
    },
    hasAddressSuggestion(state, getters) {
      return getters.filterAddressesSuggestion.length > 0;
    },
    countAddressSuggestion(state, getters) {
      return getters.filterAddressesSuggestion.length;
    },
    filterAddressesSuggestion(state) {
      if (state.household === null) {
        return state.addressesSuggestion;
      }

      if (state.household.current_address === null) {
        return state.addressesSuggestion;
      }

      return state.addressesSuggestion.filter(
        (a) => a.address_id !== state.household.current_address.address_id,
      );
    },
    hasPersonsWellPositionnated(state, getters) {
      return (
        getters.needsPositionning === false ||
        (getters.persons.length > 0 && getters.concUnpositionned.length === 0)
      );
    },
    persons(state) {
      return state.concerned.map((conc) => conc.person);
    },
    concUnpositionned(state) {
      return state.concerned.filter((conc) => conc.position === null);
    },
    positions(state) {
      return state.positions;
    },
    personByPosition: (state) => (position_id) => {
      return state.concerned
        .filter((conc) =>
          conc.position !== null ? conc.position.id === position_id : false,
        )
        .map((conc) => conc.person);
    },
    concByPosition: (state) => (position_id) => {
      return state.concerned.filter((conc) =>
        conc.position !== null ? conc.position.id === position_id : false,
      );
    },
    concByPersonId: (state) => (person_id) => {
      return state.concerned.find((conc) => conc.person.id === person_id);
    },
    needsPositionning(state) {
      return state.forceLeaveWithoutHousehold === false;
    },
    fakeHouseholdWithConcerned(state, getters) {
      if (null === state.household) {
        throw Error("cannot create fake household without household");
      }
      let h = {
        type: "household",
        members: state.household.members,
        current_address: state.household.current_address,
        current_members_id: state.household.current_members_id,
        new_members: [],
      };

      if (!getters.isHouseholdNew) {
        h.id = state.household.id;
      }

      state.concerned.forEach((c, index) => {
        if (!h.members.map((m) => m.person.id).includes(c.person.id)) {
          let m = {
            id: index * -1,
            person: c.person,
            holder: c.holder,
            position: c.position,
          };
          if (c.position === null) {
            m.position = {
              ordering: 999999,
            };
          }
          h.new_members.push(m);
        }
      });

      console.log("fake household", h);
      return h;
    },
    buildPayload: (state, getters) => {
      let conc,
        payload_conc,
        payload = {
          concerned: [],
          destination: null,
          composition: null,
        };
      if (state.forceLeaveWithoutHousehold === false) {
        payload.destination = {
          id: state.household.id,
          type: state.household.type,
        };

        if (
          getters.isHouseholdNew &&
          state.household.current_address !== null
        ) {
          payload.destination.forceAddress = {
            id: state.household.current_address.address_id,
          };
        }
      }

      for (let i in state.concerned) {
        conc = state.concerned[i];
        payload_conc = {
          person: {
            id: conc.person.id,
            type: conc.person.type,
          },
          start_date: {
            datetime:
              state.startDate === null || state.startDate === ""
                ? null
                : datetimeToISO(ISOToDate(state.startDate)),
          },
        };

        if (state.forceLeaveWithoutHousehold === false) {
          payload_conc.position = {
            id: conc.position.id,
            type: conc.position.type,
          };
          payload_conc.holder = conc.holder;
          payload_conc.comment = conc.comment;
        }

        payload.concerned.push(payload_conc);
      }

      if (getters.isHouseholdNew) {
        payload.composition = {
          household_composition_type: {
            type: state.householdCompositionType.type,
            id: state.householdCompositionType.id,
          },
          number_of_children: state.numberOfChildren,
          start_date: {
            datetime: datetimeToISO(ISOToDate(state.startDate)),
          },
          number_of_dependents: state.numberOfDependents,
          number_of_dependents_with_disabilities:
            state.numberOfDependentsWithDisabilities,
        };
      }

      return payload;
    },
  },
  mutations: {
    resetMode(state) {
      state.mode = null;
      state.household = null;
      state.forceLeaveWithoutHousehold = false;
    },
    addConcerned(state, person) {
      let persons = state.concerned.map((conc) => conc.person.id);
      if (!persons.includes(person.id)) {
        state.concerned.push({
          person,
          position: null,
          allowRemove: true,
          holder: false,
          comment: "",
        });
      } else {
        console.error("person already included");
      }
    },
    markPosition(state, { person_id, position_id }) {
      let position = state.positions.find((pos) => pos.id === position_id),
        conc = state.concerned.find((c) => c.person.id === person_id);
      conc.position = position;
      // reset position if changed:
      if (!position.allowHolder && conc.holder) {
        conc.holder = false;
      }
    },
    setComment(state, { conc, comment }) {
      conc.comment = comment;
    },
    toggleHolder(state, conc) {
      conc.holder = !conc.holder;
    },
    removePosition(state, conc) {
      conc.holder = false;
      conc.position = null;
    },
    removePerson(state, person) {
      state.concerned = state.concerned.filter(
        (c) => c.person.id !== person.id,
      );
    },
    createHousehold(state) {
      state.household = {
        type: "household",
        members: [],
        current_address: null,
        current_members_id: [],
      };
      state.mode = "new";
      state.forceLeaveWithoutHousehold = false;
    },
    removeHousehold(state) {
      state.household = null;
      state.forceLeaveWithoutHousehold = false;
    },
    setHouseholdAddress(state, address) {
      console.log("setHouseholdAddress commit", address);
      if (null === state.household) {
        console.error("no household");
        throw new Error("No household");
      }

      state.household.current_address = address;
      state.forceHouseholdNoAddress = false;
    },
    removeHouseholdAddress(state) {
      if (null === state.household) {
        console.error("no household");
        throw new Error("No household");
      }

      state.household.current_address = null;
    },
    markHouseholdNoAddress(state) {
      state.forceHouseholdNoAddress = true;
    },
    forceLeaveWithoutHousehold(state) {
      state.household = null;
      state.mode = "leave";
      state.forceLeaveWithoutHousehold = true;
    },
    selectHousehold(state, household) {
      state.household = household;
      state.mode = "existing";
      state.forceLeaveWithoutHousehold = false;
    },
    addHouseholdSuggestionByAccompanyingPeriod(state, households) {
      let existingIds = state.householdSuggestionByAccompanyingPeriod.map(
        (h) => h.id,
      );
      for (let i in households) {
        if (!existingIds.includes(households[i].id)) {
          state.householdSuggestionByAccompanyingPeriod.push(households[i]);
        }
      }
    },
    setStartDate(state, dateI) {
      state.startDate = dateI;
    },
    toggleHouseholdSuggestion(state) {
      state.showHouseholdSuggestion = !state.showHouseholdSuggestion;
    },
    toggleAddressSuggestion(state) {
      state.showAddressSuggestion = !state.showAddressSuggestion;
    },
    setWarnings(state, warnings) {
      state.warnings = warnings;
      // reset errors, which should come from servers
      state.errors.splice(0, state.errors.length);
    },
    setErrors(state, errors) {
      state.errors = errors;
    },
    setHouseholdCompositionTypes(state, types) {
      state.householdCompositionTypes = types;
    },
    setHouseholdCompositionType(state, id) {
      state.householdCompositionType = state.householdCompositionTypes.find(
        (t) => t.id === id,
      );
    },
    setNumberOfChildren(state, number) {
      state.numberOfChildren = Number.parseInt(number);
    },
    setNumberOfDependents(state, number) {
      state.numberOfDependents = Number.parseInt(number);
    },
    setNumberOfDependentsWithDisabilities(state, number) {
      state.numberOfDependentsWithDisabilities = Number.parseInt(number);
    },
    addAddressesSuggestion(state, addresses) {
      let existingIds = state.addressesSuggestion.map((a) => a.address_id);

      for (let i in addresses) {
        if (!existingIds.includes(addresses[i].address_id)) {
          state.addressesSuggestion.push(addresses[i]);
        }
      }
    },
  },
  actions: {
    addConcerned({ commit, dispatch }, person) {
      commit("addConcerned", person);
      dispatch("computeWarnings");
      dispatch("fetchAddressSuggestions");
    },
    markPosition({ commit, dispatch }, { person_id, position_id }) {
      commit("markPosition", { person_id, position_id });
      dispatch("computeWarnings");
    },
    toggleHolder({ commit, dispatch }, conc) {
      commit("toggleHolder", conc);
      dispatch("computeWarnings");
    },
    removePosition({ commit, dispatch }, conc) {
      commit("removePosition", conc);
      dispatch("computeWarnings");
    },
    removePerson({ commit, dispatch }, person) {
      commit("removePerson", person);
      dispatch("computeWarnings");
      dispatch("fetchAddressSuggestions");
    },
    removeHousehold({ commit, dispatch }) {
      commit("removeHousehold");
      dispatch("computeWarnings");
    },
    createHousehold({ commit, dispatch }) {
      commit("createHousehold");
      dispatch("computeWarnings");
    },
    setHouseholdNewAddress({ commit }, address) {
      commit("setHouseholdAddress", address);
    },
    forceLeaveWithoutHousehold({ commit, dispatch }) {
      commit("forceLeaveWithoutHousehold");
      dispatch("computeWarnings");
    },
    selectHousehold({ commit, dispatch }, h) {
      commit("selectHousehold", h);
      dispatch("computeWarnings");
    },
    setStartDate({ commit, dispatch }, date) {
      commit("setStartDate", date);
      dispatch("computeWarnings");
    },
    setComment({ commit }, payload) {
      commit("setComment", payload);
    },
    setHouseholdCompositionTypes({ commit }, payload) {
      commit("setHouseholdCompositionTypes", payload);
    },
    setHouseholdCompositionType({ commit }, payload) {
      commit("setHouseholdCompositionType", payload);
    },
    fetchHouseholdSuggestionForConcerned({ commit }, person) {
      fetchHouseholdSuggestionByAccompanyingPeriod(person.id).then(
        (households) => {
          commit("addHouseholdSuggestionByAccompanyingPeriod", households);
        },
      );
    },
    fetchAddressSuggestions({ commit, state, dispatch }) {
      for (let i in state.concerned) {
        fetchAddressSuggestionByPerson(state.concerned[i].person.id)
          .then((addresses) => {
            commit("addAddressesSuggestion", addresses);
            dispatch("fetchHouseholdSuggestionByAddresses", addresses);
          })
          .catch((e) => {
            console.log(e);
          });
      }
    },
    async fetchHouseholdSuggestionByAddresses({ commit }, addresses) {
      console.log("fetchHouseholdSuggestionByAddresses", addresses);
      // foreach address, find household suggestions
      addresses.forEach(async (a) => {
        if (a.addressReference !== null) {
          let households = await fetchHouseholdByAddressReference(
            a.addressReference,
          );
          commit("addHouseholdSuggestionByAccompanyingPeriod", households);
        } else {
          console.log("not an adresse reference");
        }
      });
    },
    computeWarnings({ commit, state, getters }) {
      let warnings = [];

      if (!getters.hasHousehold && !state.forceLeaveWithoutHousehold) {
        warnings.push({ m: "household_members_editor.add_destination", a: {} });
      }

      if (state.concerned.length === 0) {
        warnings.push({
          m: "household_members_editor.add_at_least_onePerson",
          a: {},
        });
      }

      if (
        getters.concUnpositionned.length > 0 &&
        !state.forceLeaveWithoutHousehold
      ) {
        warnings.push({
          m: "household_members_editor.give_a_position_to_every_person",
          a: {},
        });
      }

      commit("setWarnings", warnings);
    },
    confirm({ getters, commit }) {
      let payload = getters.buildPayload,
        errors = [],
        person_id,
        household_id,
        error;

      householdMove(payload).then((household) => {
        if (household === null) {
          person_id = getters.persons[0].id;
          window.location.replace(`/fr/person/${person_id}/general`);
        } else {
          if (household.type === "household") {
            household_id = household.id;

            // nothing to do anymore here, bye-bye !
            let params = new URLSearchParams(window.location.search);
            if (params.has("followAfter")) {
              window.location.replace(
                `/fr/person/household/${household_id}/summary`,
              );
            } else {
              if (params.has("returnPath")) {
                window.location.replace(params.get("returnPath"));
              } else {
                window.location.replace(
                  `/fr/person/household/${household_id}/summary`,
                );
              }
            }
          } else {
            // we assume the answer was 422...
            error = household;
            for (let i in error.violations) {
              let e = error.violations[i];
              errors.push(e.title);
            }

            commit("setErrors", errors);
          }
        }
      });
    },
  },
});

store.dispatch("computeWarnings");
store.dispatch("fetchAddressSuggestions");

if (concerned.length > 0) {
  concerned.forEach((c) => {
    store.dispatch("fetchHouseholdSuggestionForConcerned", c.person);
  });
}

fetchResults(`/api/1.0/person/houehold/composition/type.json`).then((types) => {
  store.dispatch("setHouseholdCompositionTypes", types);
});

export { store };
