import { quizApi } from "@api/quiz";
import { devlog } from "@frontend/kitui";
import { quizToEditQuizRequest } from "@model/quiz/edit";
import { Quiz, RawQuiz, rawQuizToQuiz } from "@model/quiz/quiz";
import { maxQuizSetupSteps } from "@model/quizSettings";
import { createUntypedQuestion, updateQuestion } from "@root/questions/actions";
import { useQuestionsStore } from "@root/questions/store";
import { produce } from "immer";
import { enqueueSnackbar } from "notistack";
import { NavigateFunction } from "react-router-dom";
import { RequestQueue } from "../../utils/requestQueue";
import { QuizStore, useQuizStore } from "./store";
import { QuizConfig } from "@frontend/squzanswerer";

export const setEditQuizId = (quizId: number | null) =>
  setProducedState(
    (state) => {
      state.editQuizId = quizId;
    },
    {
      type: "setEditQuizId",
      quizId,
    }
  );

export const resetEditConfig = () =>
  setProducedState((state) => {
    state.editQuizId = null;
    state.currentStep = 0;
  }, "resetEditConfig");

export const setQuizes = (quizes: RawQuiz[] | null) =>
  setProducedState(
    (state) => {
      state.quizes = quizes?.map(rawQuizToQuiz) ?? [];
    },
    {
      type: "setQuizes",
      quizes,
    }
  );

const addQuiz = (quiz: Quiz) =>
  setProducedState(
    (state) => {
      state.quizes.push(quiz);
    },
    {
      type: "addQuiz",
      quiz,
    }
  );

const removeQuiz = (quizId: string) =>
  setProducedState(
    (state) => {
      const index = state.quizes.findIndex((q) => q.id === quizId);
      if (index === -1) return;

      state.quizes.splice(index, 1);
    },
    {
      type: "removeQuiz",
      quizId,
    }
  );

const setQuizBackendId = (quizId: string, backendId: number) =>
  setProducedState(
    (state) => {
      const quiz = state.quizes.find((q) => q.id === quizId);
      if (!quiz) return;

      quiz.backendId = backendId;
    },
    {
      type: "setQuizBackendId",
      quizId,
      backendId,
    }
  );

export const incrementCurrentStep = () =>
  setProducedState(
    (state) => {
      state.currentStep = Math.min(maxQuizSetupSteps - 1, state.currentStep + 1);
    },
    {
      type: "incrementCurrentStep",
    }
  );

export const decrementCurrentStep = () =>
  setProducedState(
    (state) => {
      state.currentStep = Math.max(0, state.currentStep - 1);
    },
    {
      type: "decrementCurrentStep",
    }
  );

export const setCurrentStep = (step: number) =>
  setProducedState(
    (state) => {
      state.currentStep = Math.max(0, Math.min(maxQuizSetupSteps - 1, step));
    },
    {
      type: "setCurrentStep",
      step,
    }
  );

export const setQuizType = (quizId: string, quizType: QuizConfig["type"]) => {
  updateQuiz(quizId, (quiz) => {
    quiz.config.type = quizType;
  });
};

export const setQuizStartpageType = (quizId: string, startpageType: QuizConfig["startpageType"]) => {
  updateQuiz(quizId, (quiz) => {
    quiz.config.startpageType = startpageType;
  });
};

const REQUEST_DEBOUNCE = 200;
const requestQueue = new RequestQueue();
let requestTimeoutId: ReturnType<typeof setTimeout>;

export const updateQuiz = (quizId: string | null | undefined, updateFn: (quiz: Quiz) => void) => {
  if (!quizId) return;

  setProducedState(
    (state) => {
      const quiz = state.quizes.find((q) => q.id === quizId);
      if (!quiz) return;

      updateFn(quiz);
    },
    {
      type: "updateQuiz",
      quizId,
      updateFn: updateFn.toString(),
    }
  );

  clearTimeout(requestTimeoutId);
  requestTimeoutId = setTimeout(async () => {
    requestQueue.enqueue(`updateQuiz-${quizId}`, async () => {
      const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
      if (!quiz) return;

      const [editedQuiz, editedQuizError] = await quizApi.edit(quizToEditQuizRequest(quiz));

      if (editedQuizError || !editedQuiz) {
        devlog("Error editing quiz", editedQuizError, quizId);
        enqueueSnackbar(editedQuizError);

        return;
      }

      setQuizBackendId(quizId, editedQuiz.updated);
      setEditQuizId(editedQuiz.updated);
    });
  }, REQUEST_DEBOUNCE);
};

export const createQuiz = async (navigate: NavigateFunction) =>
  requestQueue.enqueue("createQuiz", async () => {
    const [rawQuiz, createQuizError] = await quizApi.create();

    if (createQuizError || !rawQuiz) {
      devlog("Error creating quiz", createQuizError);
      enqueueSnackbar(createQuizError);

      return;
    }

    const quiz = rawQuizToQuiz(rawQuiz);

    addQuiz(quiz);
    setEditQuizId(quiz.backendId);
    navigate("/edit");
    createUntypedQuestion(rawQuiz.id);
  });

export const deleteQuiz = async (quizId: string) =>
  requestQueue.enqueue(`deleteQuiz-${quizId}`, async () => {
    const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
    if (!quiz) return;

    const [_, deleteQuizError] = await quizApi.delete(quiz.backendId);

    if (deleteQuizError) {
      devlog("Error deleting quiz", deleteQuizError);

      enqueueSnackbar(deleteQuizError);

      return;
    }

    removeQuiz(quizId);
  });
export const updateRootContentId = (quizId: string, id: string) => {
  if (id.length === 0) {
    //дерева больше не существует, все результаты неактивны кроме результата линейности
    useQuestionsStore.getState().questions.forEach((q) => {
      if (q.type !== null && q.type === "result") {
        if (q.content.rule.parentId === "line") {
          if (q.content.usage === false)
            updateQuestion(q.id, (q) => {
              q.content.usage = true;
            });
        } else {
          updateQuestion(q.id, (q) => {
            q.content.usage = false;
          });
        }
      }
    });
  } else {
    //было создано дерево, результат линейности неактивен
    useQuestionsStore.getState().questions.forEach((q) => {
      if (q.type !== null && q.content.rule.parentId === "line") {
        updateQuestion(q.id, (q) => {
          q.content.usage = false;
        });
      }
    });
  }

  updateQuiz(quizId, (quiz) => {
    quiz.config.haveRoot = id;
  });
};

export const copyQuiz = async (quizId: string) =>
  requestQueue.enqueue(`copyQuiz`, async () => {
    const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
    if (!quiz) return;

    const [copiedQuiz, copyError] = await quizApi.copy(quiz.backendId);

    if (copyError || !copiedQuiz) {
      devlog("Error copying quiz", copyError);
      enqueueSnackbar(copyError);

      return;
    }

    let newQuiz: Quiz = {
      ...quiz,
      id: String(copiedQuiz.updated),
      session_count: 0,
      passed_count: 0,
    };

    setProducedState(
      (state) => {
        state.quizes.unshift(newQuiz);
      },
      { type: "addQuiz", quiz }
    );
  });

export const uploadQuizImage = async (quizId: string, blob: Blob, updateFn: (quiz: Quiz, imageId: string) => void) => {
  const quiz = useQuizStore.getState().quizes.find((q) => q.id === quizId);
  if (!quiz) return;

  const [addedImages, addImagesError] = await quizApi.addImages(quiz.backendId, blob);

  if (addImagesError || !addedImages) {
    devlog("Error uploading quiz image", addImagesError);
    enqueueSnackbar(addImagesError);

    return;
  }

  const values = Object.values(addedImages);
  if (values.length !== 1) {
    console.warn("Error uploading image");
    return;
  }

  const imageId = values[0];

  updateQuiz(quizId, (quiz) => {
    updateFn(
      quiz,
      `https://s3.timeweb.cloud/3c580be9-cf31f296-d055-49cf-b39e-30c7959dc17b/squizimages/${quiz.qid}/${imageId}`
    );
  });
};

function setProducedState<A extends string | { type: string }>(recipe: (state: QuizStore) => void, action?: A) {
  useQuizStore.setState((state) => produce(state, recipe), false, action);
}
