<template>
    <div v-for="(q, i) in questions" :key="i">
        <transition appear name="fade" mode="out-in">
            <buttonQuestion
                v-if="isQuestionVisible(q)"
                class="radioQuestion"
                :class="isCurrentQuestion(q) && 'current-question'"
                :questionText="q.questionText"
                :answers="q.answers"
                :groupName="`question-${index}-${q.questionSequence}`"
                v-model="q.answerSelected"
                @update:modelValue="handleAnswer(q, $event)"
                isRequired
                :validationRules="validationRules" />
        </transition>
    </div>
</template>

<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import { useValidateForm } from "vee-validate";
import {
    mapQuestionAnswersForChain,
    normalizeAnswerSelectedValue,
} from "@/helpers/question-chain-helper";

export default {
    name: "questionChain",
    data() {
        return {
            currentQuestionNum: 0,
            questions: [],
        };
    },
    props: {
        questionData: Array,
        validationRules: String,
        modelValue: Object,
        index: Number,
        answerKey: String,
        hasSavedAnswer: Boolean,
        hasDownstreamSavedAnswers: Boolean,
    },
    async created() {
        // do a test validation check upon create to prevent out of sync / incorrect valid states
        await useValidateForm(); // NOTE: needs to have async/await here; tested and won't work without it

        this.questionData.map((q, i) => {
            const answers = mapQuestionAnswersForChain(q);
            const question = {
                questionText: q.questionText,
                questionSequence: q.questionSequence,
                answers,
                answerSelected: normalizeAnswerSelectedValue(q.answerSelected, answers),
            };
            if (!q.suppressThisQuestion) {
                this.questions.push(question);
            }
        });

        if (this.questions.length > 0) {
            this.initializeCurrentQuestionNum();
            this.scrollCurrentQuestionIntoView();
        }
    },
    methods: {
        getQuestionSequence(question) {
            return Number(question?.questionSequence);
        },
        isCurrentQuestion(question) {
            return this.getQuestionSequence(question) === Number(this.currentQuestionNum);
        },
        isQuestionVisible(question) {
            return !!question.answerSelected || this.isCurrentQuestion(question);
        },
        initializeCurrentQuestionNum() {
            const pendingNextQuestion = [...this.questions]
                .reverse()
                .find((question) => question.answerSelected?.includes("|nextQuestion|"));

            if (pendingNextQuestion) {
                const nextQuestionSequence = Number(
                    pendingNextQuestion.answerSelected.split("|")[2]
                );

                if (
                    this.questions.some(
                        (question) => this.getQuestionSequence(question) === nextQuestionSequence
                    )
                ) {
                    this.currentQuestionNum = nextQuestionSequence;
                    return;
                }
            }

            const firstUnanswered = this.questions.find((question) => !question.answerSelected);

            if (firstUnanswered) {
                this.currentQuestionNum = this.getQuestionSequence(firstUnanswered);
            }
        },
        scrollCurrentQuestionIntoView() {
            this.$nextTick(() => {
                document.querySelector(".current-question")?.scrollIntoView({ behavior: "smooth" });
            });
        },
        syncAnswerSelectedToQuestionData(questionSequence, answerSelected) {
            const sourceQuestion = this.questionData?.find(
                (q) => this.getQuestionSequence(q) === Number(questionSequence)
            );

            if (sourceQuestion) {
                sourceQuestion.answerSelected = answerSelected;
            }
        },
        getProblemQuestionIdFromSelectedAnswer(question, selectedAnswer) {
            if (!question?.answers || !selectedAnswer) {
                return null;
            }

            const matchedAnswer = question.answers.find(
                (answer) => answer.value === selectedAnswer
            );

            return matchedAnswer?.problemQuestionId ?? null;
        },
        handleAnswer(question, returnedAnswer) {
            /*
                returnedAnswer example format:
                "1|answer|DD11132|Yes"
            */

            question.answerSelected = returnedAnswer;
            this.syncAnswerSelectedToQuestionData(question.questionSequence, returnedAnswer);
            const questionChainAnswer = this.getQuestionChainAnswerIfComplete(returnedAnswer);

            if (!questionChainAnswer) {
                return;
            }

            const shouldNotifyParent =
                !questionChainAnswer.incomplete ||
                this.hasSavedAnswer ||
                this.hasDownstreamSavedAnswers;

            if (shouldNotifyParent) {
                this.$emit("update:modelValue", questionChainAnswer);
            }
        },
        getQuestionChainAnswerIfComplete(returnedAnswer) {
            // this method will return either a final answer or Boolean false
            if (!returnedAnswer) {
                return false;
            }

            // returnedAnswer examples:
            //   "1|nextQuestion|3|No"
            //   "5|answer|DW02104|Yes"

            const returnedAnswerArray = returnedAnswer.split("|");
            const questionNum = Number(returnedAnswerArray[0]);
            const questionType = returnedAnswerArray[1];
            const questionAnswer = returnedAnswerArray[2];
            const answeredQuestions = [];

            this.questions.forEach((q) => {
                const questionSequence = this.getQuestionSequence(q);

                // find this question and mark it as "answered" by populating answerSelected
                if (questionSequence === questionNum) {
                    q.answerSelected = returnedAnswer;
                    this.syncAnswerSelectedToQuestionData(questionSequence, returnedAnswer);
                }
                // remove all answers AFTER this question...
                //      (needed in case user is changing previously answered questions)
                if (questionSequence > questionNum) {
                    delete q.answerSelected;
                    this.syncAnswerSelectedToQuestionData(questionSequence, "");
                }
                if (q.answerSelected) {
                    answeredQuestions.push({
                        questionText: q.questionText,
                        selectedAnswer: q.answerSelected,
                        selectedAnswerText: q.answerSelected.split("|")[3],
                        questionNum: q.questionSequence,
                        problemQuestionId: this.getProblemQuestionIdFromSelectedAnswer(
                            q,
                            q.answerSelected
                        ),
                    });
                }
            });

            // return incomplete answer if there's a nextQuestion... or return final answers (truthy)
            if (questionType === "nextQuestion") {
                // update to next question index
                this.currentQuestionNum = Number(questionAnswer);
                this.scrollCurrentQuestionIntoView();
                return {
                    incomplete: true,
                    answeredQuestions,
                    index: this.index,
                };
            } else {
                // reset current question index (removes .current-question class)
                this.currentQuestionNum = 0; // reset count
                const answeredQuestion = this.questions.find(
                    (q) => this.getQuestionSequence(q) === questionNum
                );

                // return an object with the part answer, all the answered questions, and the part index
                return {
                    answerResult: questionAnswer,
                    problemQuestionId: this.getProblemQuestionIdFromSelectedAnswer(
                        answeredQuestion,
                        returnedAnswer
                    ),
                    answeredQuestions: answeredQuestions,
                    index: this.index,
                };
            }
        },
    },
    components: {
        buttonQuestion,
    },
};
</script>
