import { createStore } from "vuex";
import {
  dateToISO,
  ISOToDate,
  datetimeToISO,
  ISOToDatetime,
  intervalDaysToISO,
  intervalISOToDays,
} from "ChillMainAssets/chill/js/date";
import { findSocialActionsBySocialIssue } from "ChillPersonAssets/vuejs/_api/SocialWorkSocialAction.js";
import { create } from "ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js";
import { fetchResults, makeFetch } from "ChillMainAssets/lib/api/apiMethods.ts";
import { fetchTemplates } from "ChillDocGeneratorAssets/api/pickTemplate.js";
import {
  duplicate,
  duplicateDocumentToEvaluation,
  moveDocumentToEvaluation,
} from "../_api/accompanyingCourseWorkEvaluationDocument";

const debug = process.env.NODE_ENV !== "production";

const store = createStore({
  strict: debug,
  state: {
    work: window.accompanyingCourseWork,
    startDate:
      window.accompanyingCourseWork.startDate !== null
        ? dateToISO(new Date(window.accompanyingCourseWork.startDate.datetime))
        : null,
    endDate:
      window.accompanyingCourseWork.endDate !== null
        ? dateToISO(new Date(window.accompanyingCourseWork.endDate.datetime))
        : null,
    note: window.accompanyingCourseWork.note,
    privateComment: window.accompanyingCourseWork.privateComment,
    goalsPicked: window.accompanyingCourseWork.goals,
    goalsForAction: [],
    resultsPicked: window.accompanyingCourseWork.results,
    resultsForAction: [],
    resultsForGoal: [],
    evaluationsPicked: [],
    evaluationsForAction: [],
    templatesAvailablesForAction: [],
    templatesAvailablesForEvaluation: new Map([]),
    personsPicked: window.accompanyingCourseWork.persons,
    personsReachables:
      window.accompanyingCourseWork.accompanyingPeriod.participations
        .filter((p) => p.endDate == null)
        .map((p) => p.person),
    handlingThirdParty: window.accompanyingCourseWork.handlingThierParty,
    thirdParties: window.accompanyingCourseWork.thirdParties,
    referrers: window.accompanyingCourseWork.referrers,
    isPosting: false,
    errors: [],
    me: null,
    version: window.accompanyingCourseWork.version,
  },
  getters: {
    socialAction(state) {
      return state.work.socialAction;
    },
    hasResultsForAction(state) {
      return state.resultsForAction.length > 0;
    },
    resultsForGoal: (state) => (goal) => {
      let founds = state.resultsForGoal.filter((r) => r.goalId === goal.id);

      return founds === undefined ? [] : founds;
    },
    resultsPickedForGoal: (state) => (goal) => {
      let found = state.goalsPicked.find((g) => g.goal.id === goal.id);

      return found === undefined ? [] : found.results;
    },
    hasHandlingThirdParty(state) {
      return state.handlingThirdParty !== null;
    },
    hasReferrers(state) {
      return state.referrers.length > 0;
    },
    hasThirdParties(state) {
      return state.thirdParties.length > 0;
    },
    getTemplatesAvailablesForEvaluation: (state) => (evaluation) => {
      if (state.templatesAvailablesForEvaluation.has(evaluation.id)) {
        return state.templatesAvailablesForEvaluation.get(evaluation.id);
      }

      return [];
    },
    getPreviousPersons(state) {
      return state.personsPicked.filter(
        (p) => !state.personsReachables.map((pr) => pr.id).includes(p.id),
      );
    },
    buildPayload(state) {
      return {
        type: "accompanying_period_work",
        id: state.work.id,
        version: state.version,
        startDate:
          state.startDate === null || state.startDate === ""
            ? null
            : {
                datetime: datetimeToISO(ISOToDate(state.startDate)),
              },
        endDate:
          state.endDate === null || state.endDate === ""
            ? null
            : {
                datetime: datetimeToISO(ISOToDate(state.endDate)),
              },
        note: state.note,
        privateComment: state.privateComment,
        persons: state.personsPicked.map((p) => ({ id: p.id, type: p.type })),
        handlingThierParty:
          state.handlingThirdParty === null
            ? null
            : {
                id: state.handlingThirdParty.id,
                type: state.handlingThirdParty.type,
              },
        results: state.resultsPicked.map((r) => ({ id: r.id, type: r.type })),
        thirdParties: state.thirdParties.map((t) => ({
          id: t.id,
          type: t.type,
        })),
        referrers: state.referrers.map((t) => ({ id: t.id, type: t.type })),
        goals: state.goalsPicked.map((g) => {
          let o = {
            type: g.type,
            note: g.note,
            goal: {
              type: g.goal.type,
              id: g.goal.id,
            },
            results: g.results.map((r) => ({ id: r.id, type: r.type })),
          };
          if (g.id !== undefined) {
            o.id = g.id;
          }
          return o;
        }),
        accompanyingPeriodWorkEvaluations: state.evaluationsPicked.map((e) => {
          let o = {
            type: e.type,
            key: e.key,
            evaluation: {
              id: e.evaluation.id,
              type: e.evaluation.type,
            },
            startDate:
              e.startDate === null || e.startDate === ""
                ? null
                : { datetime: datetimeToISO(ISOToDate(e.startDate)) },
            endDate:
              e.endDate === null || e.endDate === ""
                ? null
                : { datetime: datetimeToISO(ISOToDate(e.endDate)) },
            maxDate:
              e.maxDate === null || e.maxDate === ""
                ? null
                : { datetime: datetimeToISO(ISOToDate(e.maxDate)) },
            warningInterval: intervalDaysToISO(e.warningInterval),
            timeSpent: e.timeSpent,
            comment: e.comment,
            documents: e.documents,
          };
          if (e.id !== undefined) {
            o.id = e.id;
          }

          return o;
        }),
      };
    },
  },
  mutations: {
    setWhoAmiI(state, me) {
      state.me = me;
    },
    setEvaluationsPicked(state, evaluations) {
      state.evaluationsPicked = evaluations.map((e, index) => {
        var k = Object.assign(e, {
          key: index,
          editEvaluation: false,
          startDate:
            e.startDate !== null
              ? dateToISO(new Date(e.startDate.datetime))
              : null,
          endDate:
            e.endDate !== null ? dateToISO(new Date(e.endDate.datetime)) : null,
          maxDate:
            e.maxDate !== null ? dateToISO(new Date(e.maxDate.datetime)) : null,
          warningInterval:
            e.warningInterval !== null
              ? intervalISOToDays(e.warningInterval)
              : null,
          timeSpent: e.timeSpent !== null ? e.timeSpent : null,
          documents: e.documents.map((d, docIndex) => {
            return Object.assign(d, {
              key: docIndex,
            });
          }),
        });

        return k;
      });
    },
    setStartDate(state, date) {
      state.startDate = date;
    },
    setEndDate(state, date) {
      state.endDate = date;
    },
    setResultsForAction(state, results) {
      state.resultsForAction = results;
    },
    setResultsForGoal(state, { goal, results }) {
      state.goalsForAction.push(goal);
      for (let i in results) {
        let r = results[i];
        r.goalId = goal.id;
        state.resultsForGoal.push(r);
      }
    },
    setEvaluationsForAction(state, results) {
      state.evaluationsForAction = results;
    },
    addResultPicked(state, result) {
      state.resultsPicked.push(result);
    },
    removeResultPicked(state, result) {
      state.resultsPicked = state.resultsPicked.filter(
        (r) => r.id !== result.id,
      );
    },
    addGoal(state, goal) {
      let g = {
        type: "accompanying_period_work_goal",
        goal: goal,
        note: "",
        results: [],
      };
      const tmpIndex = () => {
        let ar = state.goalsPicked.map((g) => g.id),
          s = Math.min(...ar);
        return s < 0 ? s : 0;
      };
      g.id = tmpIndex() - 1;
      state.goalsPicked.push(g);
    },
    removeGoal(state, goal) {
      state.goalsPicked = state.goalsPicked.filter((g) => g.id !== goal.id);
    },
    addResultForGoalPicked(state, { goal, result }) {
      let found = state.goalsPicked.find((g) => g.goal.id === goal.id);

      if (found === undefined) {
        return;
      }

      found.results.push(result);
    },
    removeResultForGoalPicked(state, { goal, result }) {
      let found = state.goalsPicked.find((g) => g.goal.id === goal.id);

      if (found === undefined) {
        return;
      }

      found.results = found.results.filter((r) => r.id !== result.id);
    },
    addDocument(state, payload) {
      // associate version to stored object
      payload.document.storedObject.currentVersion =
        payload.stored_object_version;

      let evaluation = state.evaluationsPicked.find(
        (e) => e.key === payload.key,
      );

      evaluation.documents.push(
        Object.assign(payload.document, {
          key: evaluation.documents.length + 1,
          workflows_availables:
            state.work.workflows_availables_evaluation_documents,
          workflows: [],
        }),
      );
    },
    removeDocument(state, { key, document }) {
      let evaluation = state.evaluationsPicked.find((e) => e.key === key);
      if (evaluation === undefined) {
        return;
      }
      evaluation.documents = evaluation.documents.filter(
        (d) => d.key !== document.key,
      );
    },
    addDuplicatedDocument(state, { document, evaluation_key }) {
      let evaluation = state.evaluationsPicked.find(
        (e) => e.key === evaluation_key,
      );
      document.key = evaluation.documents.length + 1;
      evaluation.documents.splice(0, 0, document);
    },
    addDuplicatedDocumentToEvaluation(state, { document, evaluation }) {
      let evaluationDest = state.evaluationsPicked.find(
        (e) => e.id === evaluation.id,
      );
      if (evaluationDest) {
        console.log("add duplicated document to evaluation", evaluationDest);
        document.key = evaluationDest.documents.length + 1;
        evaluationDest.documents.splice(0, 0, document);
      }
    },
    moveDocumentToEvaluation(
      state,
      { evaluationInitial, evaluationDest, document },
    ) {
      let evaluationA = state.evaluationsPicked.find(
        (e) => e.id === evaluationInitial.id,
      );
      let evaluationB = state.evaluationsPicked.find(
        (e) => e.id === evaluationDest.id,
      );

      if (evaluationB) {
        // add document to chosen evaluation if evaluation is part of the same social work
        document.key = evaluationB.documents.length + 1;
        evaluationB.documents.splice(0, 0, document);
      }

      // remove document from original evaluation
      const indexToRemove = evaluationA.documents.findIndex(
        (doc) => doc.id === document.id,
      );
      if (indexToRemove !== -1) {
        evaluationA.documents.splice(indexToRemove, 1);
      }
    },
    /**
     * Replaces a document in the state with a new document.
     *
     * @param {object} state - The current state of the application.
     * @param {{key: number, oldDocument: {key: number}, stored_object_version: StoredObjectVersion}} payload - The object containing the information about the document to be replaced.
     * @return {void} - returns nothing.
     */
    replaceDocument(state, payload) {
      let evaluation = state.evaluationsPicked.find(
        (e) => e.key === payload.key,
      );
      if (evaluation === undefined) {
        return;
      }

      let doc = evaluation.documents.find(
        (d) => d.key === payload.oldDocument.key,
      );

      if (typeof doc === "undefined") {
        console.error("doc not found");
        return;
      }

      doc.storedObject.currentVersion = payload.stored_object_version;
      return;
      let newDocument = Object.assign(payload.document, {
        key: evaluation.documents.length + 1,
        workflows_availables:
          state.work.workflows_availables_evaluation_documents,
        workflows: [],
      });
      evaluation.documents = evaluation.documents.map((d) =>
        d.id === payload.oldDocument.id ? newDocument : d,
      );
    },
    addEvaluation(state, evaluation) {
      let e = {
        type: "accompanying_period_work_evaluation",
        key: state.evaluationsPicked.length + 1,
        evaluation: evaluation,
        startDate: dateToISO(new Date()),
        endDate: null,
        maxDate: null,
        warningInterval: null,
        timeSpent: null,
        comment: "",
        editEvaluation: true,
        workflows_availables: state.work.workflows_availables_evaluation,
        documents: [],
        workflows: [],
      };
      state.evaluationsPicked.push(e);
    },
    removeEvaluation(state, evaluation) {
      state.evaluationsPicked = state.evaluationsPicked.filter(
        (e) => e.key !== evaluation.key,
      );
    },
    setEvaluationStartDate(state, { key, date }) {
      state.evaluationsPicked.find((e) => e.key === key).startDate = date;
    },
    setEvaluationEndDate(state, { key, date }) {
      console.log("commit date", date);
      state.evaluationsPicked.find((e) => e.key === key).endDate = date;
    },
    setEvaluationMaxDate(state, { key, date }) {
      state.evaluationsPicked.find((e) => e.key === key).maxDate = date;
    },
    setEvaluationWarningInterval(state, { key, days }) {
      state.evaluationsPicked.find((e) => e.key === key).warningInterval = days;
    },
    setEvaluationTimeSpent(state, { key, time }) {
      state.evaluationsPicked.find((e) => e.key === key).timeSpent = time;
    },
    setEvaluationComment(state, { key, comment }) {
      state.evaluationsPicked.find((e) => e.key === key).comment = comment;
    },
    toggleEvaluationEdit(state, { key }) {
      let evaluation = state.evaluationsPicked.find((e) => e.key === key);
      evaluation.editEvaluation = !evaluation.editEvaluation;
    },
    setTemplatesForEvaluation(state, { templates, evaluation }) {
      state.templatesAvailablesForEvaluation.set(evaluation.id, templates);
    },
    setTemplatesAvailablesForAction(state, templates) {
      state.templatesAvailablesForAction = templates;
    },
    setPersonsPickedIds(state, ids) {
      state.personsPicked = state.personsReachables.filter((p) =>
        ids.includes(p.id),
      );
    },
    setNote(state, note) {
      state.note = note;
    },
    setPrivateComment(state, privateComment) {
      state.privateComment = privateComment;
    },
    setHandlingThirdParty(state, thirdParty) {
      state.handlingThirdParty = thirdParty;
    },
    addThirdParties(state, thirdParties) {
      // filter to remove existing thirdparties
      let ids = state.thirdParties.map((t) => t.id);
      let unexistings = thirdParties.filter((t) => !ids.includes(t.id));

      for (let i in unexistings) {
        state.thirdParties.push(unexistings[i]);
      }
    },
    updateThirdParty(state, thirdParty) {
      for (let t of state.thirdParties) {
        if (t.id === thirdParty.id) {
          state.thirdParties = state.thirdParties.filter(
            (t) => t.id !== thirdParty.id,
          );
          state.thirdParties.push(thirdParty);
        }
      }
    },
    removeThirdParty(state, thirdParty) {
      state.thirdParties = state.thirdParties.filter(
        (t) => t.id !== thirdParty.id,
      );
    },
    addReferrers(state, referrers) {
      let ids = state.referrers.map((t) => t.id);
      let unexistings = referrers.filter((t) => !ids.includes(t.id));

      for (let i in unexistings) {
        state.referrers.push(unexistings[i]);
      }
    },
    removeReferrer(state, user) {
      state.referrers = state.referrers.filter((u) => u.id !== user.id);
    },
    setErrors(state, errors) {
      state.errors = errors;
    },
    setIsPosting(state, st) {
      state.isPosting = st;
    },
    updateDocumentTitle(state, payload) {
      if (payload.id === 0) {
        state.evaluationsPicked
          .find((e) => e.key === payload.evaluationKey)
          .documents.find((d) => d.key === payload.key).title = payload.title;
      } else {
        state.evaluationsPicked
          .find((e) => e.key === payload.evaluationKey)
          .documents.find((d) => d.id === payload.id).title = payload.title;
      }
    },
    statusDocumentChanged(state, { newStatus, key }) {
      const e = state.evaluationsPicked.find((e) => e.key === key);
      if (typeof e === "undefined") {
        console.error("evaluation not found for given key", { key });
      }

      const doc = e.documents.find((d) => d.storedObject?.id === newStatus.id);
      if (typeof doc === "undefined") {
        console.error("document not found", { newStatus });
      }

      doc.storedObject.status = newStatus.status;
      doc.storedObject.type = newStatus.type;
      doc.storedObject.filename = newStatus.filename;
    },
  },
  actions: {
    getWhoAmI({ commit }) {
      let url = `/api/1.0/main/whoami.json`;
      window
        .fetch(url)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
          throw {
            m: "Error while retriving results for goal",
            s: response.status,
            b: response.body,
          };
        })
        .then((data) => {
          commit("setWhoAmiI", data);
        });
    },
    updateThirdParty({ commit }, payload) {
      commit("updateThirdParty", payload);
    },
    getReachablesGoalsForAction({ getters, commit, dispatch }) {
      let socialActionId = getters.socialAction.id,
        url = `/api/1.0/person/social-work/goal/by-social-action/${socialActionId}.json`;
      window
        .fetch(url)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
          throw {
            m: "Error while retriving goal for social action",
            s: response.status,
            b: response.body,
          };
        })
        .then((data) => {
          for (let i in data.results) {
            dispatch("getReachablesResultsForGoal", data.results[i]);
          }
        })
        .catch((errors) => {
          commit("addErrors", errors);
        });
    },
    getReachablesResultsForGoal({ commit }, goal) {
      let url = `/api/1.0/person/social-work/result/by-goal/${goal.id}.json`;
      window
        .fetch(url)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }

          throw {
            m: "Error while retriving results for goal",
            s: response.status,
            b: response.body,
          };
        })
        .then((data) => {
          commit("setResultsForGoal", { goal, results: data.results });
        });
    },
    getReachablesResultsForAction({ getters, commit }) {
      let socialActionId = getters.socialAction.id,
        url = `/api/1.0/person/social-work/result/by-social-action/${socialActionId}.json`;
      window
        .fetch(url)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }

          throw {
            m: "Error while retriving results for social action",
            s: response.status,
            b: response.body,
          };
        })
        .then((data) => {
          commit("setResultsForAction", data.results);
        });
    },
    getReachablesEvaluationsForAction({ getters, commit }) {
      let socialActionId = getters.socialAction.id,
        url = `/api/1.0/person/social-work/evaluation/by-social-action/${socialActionId}.json`;
      window
        .fetch(url)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
          throw {
            m: "Error while retriving evaluations for social action",
            s: response.status,
            b: response.body,
          };
        })
        .then((data) => {
          commit("setEvaluationsForAction", data.results);
        });
    },
    addEvaluation({ commit, dispatch }, evaluation) {
      commit("addEvaluation", evaluation);
      dispatch("fetchTemplatesAvailablesForEvaluation", evaluation);
    },
    fetchTemplatesAvailablesForEvaluation({ commit, state }, evaluation) {
      if (!state.templatesAvailablesForEvaluation.has(evaluation.id)) {
        // commit an empty array to avoid parallel fetching for same evaluation id
        commit("setTemplatesForEvaluation", { templates: [], evaluation });
        fetchResults(
          `/api/1.0/person/docgen/template/by-evaluation/${evaluation.id}.json`,
        ).then((templates) => {
          commit("setTemplatesForEvaluation", { templates, evaluation });
        });
      }
    },
    addDocument({ commit }, payload) {
      commit("addDocument", payload);
    },
    async duplicateDocument({ commit }, { document, evaluation_key }) {
      const newDoc = await duplicate(document.id);
      commit("addDuplicatedDocument", { document: newDoc, evaluation_key });
    },
    async duplicateDocumentToEvaluation({ commit }, { document, evaluation }) {
      try {
        const newDoc = await duplicateDocumentToEvaluation(
          document.id,
          evaluation.id,
        );
        commit("addDuplicatedDocumentToEvaluation", {
          document: newDoc,
          evaluation,
        });

        return newDoc;
      } catch (error) {
        console.error("Failed to move document:", error);
        throw error;
      }
    },
    async moveDocumentToEvaluation(
      { commit },
      { evaluationInitial, evaluationDest, document },
    ) {
      try {
        const response = await moveDocumentToEvaluation(
          document.id,
          evaluationDest.id,
        );
        commit("moveDocumentToEvaluation", {
          evaluationInitial,
          evaluationDest,
          document,
        });

        return response;
      } catch (error) {
        console.error("Failed to move document:", error);
        throw error;
      }
    },
    removeDocument({ commit }, payload) {
      commit("removeDocument", payload);
    },
    replaceDocument({ commit }, payload) {
      commit("replaceDocument", payload);
    },
    submit({ getters, state, commit }, callback) {
      let payload = getters.buildPayload,
        params = new URLSearchParams({ entity_version: state.version }),
        url = `/api/1.0/person/accompanying-course/work/${state.work.id}.json?${params}`;
      commit("setIsPosting", true);

      // console.log('the social action', payload);

      return makeFetch("PUT", url, payload)
        .then((data) => {
          if (typeof callback !== "undefined") {
            return callback(data);
          } else {
            // console.log('payload', payload.privateComment)
            // console.info('nothing to do here, bye bye');
            window.location.assign(
              `/fr/person/accompanying-period/${state.work.accompanyingPeriod.id}/work`,
            );
          }
        })
        .catch((error) => {
          console.log("error", error);
          commit("setIsPosting", false);
          throw error;
        });
    },
    updateDocumentTitle({ commit }, payload) {
      commit("updateDocumentTitle", payload);
    },
  },
});

store.commit(
  "setEvaluationsPicked",
  window.accompanyingCourseWork.accompanyingPeriodWorkEvaluations,
);
store.dispatch("getReachablesResultsForAction");
store.dispatch("getReachablesGoalsForAction");
store.dispatch("getReachablesEvaluationsForAction");
store.dispatch("getWhoAmI");

store.state.evaluationsPicked.forEach((evaluation) => {
  store.dispatch(
    "fetchTemplatesAvailablesForEvaluation",
    evaluation.evaluation,
  );
});

fetchTemplates(
  "Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWork",
).then((templates) => {
  store.commit("setTemplatesAvailablesForAction", templates);
});

export { store };
