import { FormServerErrors } from "@/components/form-common/form-server-errors";
import { FormSubmit } from "@/components/form-common/form-submit";
import { QuizQuestion } from "@/components/lab-quiz/question";
import { useLabInstanceContext } from "@/components/labs/lab-instance-context";
import { useLocaleFunction } from "@/hooks/use-localed";
import { client } from "@/lib/api-client";
import {
  getLabInstanceQuizSubmissions,
  type QuizPart,
  submitLabInstanceQuiz,
} from "@/lib/api/labs.v2";
import { handleFormElementSubmitEvent, handleSubmitErrors } from "@/lib/form";
import { renderRemarkInline } from "@/lib/remark-inline";
import { useForm } from "@tanstack/react-form";
import { useQuery } from "@tanstack/react-query";
import { useEffect, useId, useMemo } from "react";
import { z } from "zod";

export function Quiz({ preview, quiz }: { quiz: QuizPart; preview: boolean }) {
  if (preview) {
    return <QuizPreview quiz={quiz} />;
  } else {
    return <QuizInstance quiz={quiz} />;
  }
}

function QuizInstance({ quiz }: { quiz: QuizPart }) {
  const id = useId();

  const { lab } = useLabInstanceContext();
  const t = useLocaleFunction();

  const { data: prevAnswers, isLoading } = useQuery({
    queryKey: ["lab.instances", lab.id, "quizzes", quiz.content.slug],
    queryFn: () =>
      getLabInstanceQuizSubmissions(lab.id, t.locale, quiz.content.slug),
    refetchOnWindowFocus: false,
  });

  const { title, description } = useMemo(() => {
    const title = renderRemarkInline(quiz.content.title, true);
    const description = renderRemarkInline(quiz.content.description);

    return {
      title,
      description,
    };
  }, [quiz.content.title, quiz.content.description]);

  const schema = useMemo(() => {
    return z.object({
      answers: z.array(z.number().array().min(1)),
    });
  }, []);

  const defaultValues = useMemo(() => {
    return {
      answers: prevAnswers
        ? prevAnswers.answers.map((a) => a.user_answer)
        : new Array(quiz.content.questions.length)
            .fill(0)
            .map(() => [] as number[]),
    };
  }, [quiz.content.questions.length, prevAnswers]);

  const form = useForm({
    validators: {
      onSubmit: schema,
    },
    onSubmit: async ({ formApi, value }) => {
      await handleSubmitErrors(formApi, async () => {
        const details = await submitLabInstanceQuiz(
          lab.id,
          t.locale,
          quiz.content.slug,
          value
        );
        client.setQueryData(
          ["lab.instances", lab.id, "quizzes", quiz.content.slug],
          details
        );
      });
    },
    defaultValues,
  });

  useEffect(() => {
    if (prevAnswers) {
      form.reset(
        {
          answers: prevAnswers.answers.map((a) => a.user_answer),
        },
        {
          keepDefaultValues: false,
        }
      );
    }
  }, [form, prevAnswers]);

  const disabled =
    isLoading ||
    !form.state.canSubmit ||
    (quiz.content.allow_repeat_submission ? false : prevAnswers != null);

  const showSubmit =
    quiz.content.allow_repeat_submission || prevAnswers == null;

  return (
    <>
      <h2>{title}</h2>
      {description}
      <form id={id} onSubmit={handleFormElementSubmitEvent(form)}>
        <ol>
          {quiz.content.questions.map((question, index) => (
            <form.Field key={index} name={`answers[${index}]`}>
              {(fieldApi) => (
                <QuizQuestion
                  disabled={disabled}
                  question={question}
                  value={fieldApi.state.value}
                  onValueChange={fieldApi.handleChange}
                  isCorrect={prevAnswers?.answers[index].is_correct}
                  correctAnswer={prevAnswers?.answers[index].correct_answer}
                  explanation={prevAnswers?.answers[index].explanation}
                />
              )}
            </form.Field>
          ))}
        </ol>
      </form>
      <FormServerErrors
        title={t("lab.alerts.failed-to-submit-quiz")}
        formApi={form}
      />
      {showSubmit && (
        <FormSubmit
          variant="secondary"
          formApi={form}
          form={id}
          disabled={disabled}
        >
          {t("lab.quiz.submit")}
        </FormSubmit>
      )}
    </>
  );
}

function QuizPreview({ quiz }: { quiz: QuizPart }) {
  const { title, description } = useMemo(() => {
    const title = renderRemarkInline(quiz.content.title, true);
    const description = renderRemarkInline(quiz.content.description);

    return {
      title,
      description,
    };
  }, [quiz.content.title, quiz.content.description]);

  return (
    <>
      <h2>{title}</h2>
      {description}
      <ol>
        {quiz.content.questions.map((question, index) => (
          <QuizQuestion
            key={index}
            disabled
            question={question}
            value={[]}
            onValueChange={() => {}}
          />
        ))}
      </ol>
    </>
  );
}
