import { shallowMount } from "@vue/test-utils";
import questionChain from "./question-chain.vue";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";

jest.mock(
    "@/store",
    () => {
        return {};
    },
    { virtual: true }
);

describe("Question Chain component", () => {
    describe("on create...", () => {
        test("Should populate questions data array", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const expectedFirstQuestionAnswer = {
                answerResult: "DB09410",
                buttonLabel: "Yes",
                nextQuestionSequence: null,
                questionSequence: 1,
                questionType: "answer",
                value: "1|answer|DB09410|Yes",
            };

            //Act
            await nextTick();

            //Assert
            expect(wrapper.vm.questions[0].answers[0]).toMatchObject(expectedFirstQuestionAnswer);
        });

        test("Should not include suppressed questions on questions data array", async () => {
            //Arrange
            const { wrapper } = setupMocks({});

            await wrapper.setData({
                questionData: [
                    {
                        questionSequence: 1,
                        questionText: "Question here?",
                        answers: [
                            {
                                answerResult: "DB09410",
                                answerText: "Yes",
                                nextQuestionSequence: null,
                            },
                            {
                                answerResult: "DB10840",
                                answerText: "No",
                                nextQuestionSequence: null,
                            },
                        ],
                        suppressThisQuestion: true,
                    },
                ],
            });

            //Act
            await nextTick();

            //Assert
            expect(wrapper.vm.questions[0]).toBeFalsy();
        });
    });

    describe("method handleAnswer...", () => {
        test("should run getQuestionChainAnswerIfComplete", () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testQuestion = {};
            const testReturnedAnswer = "aReturnedAnswer";
            wrapper.vm.getQuestionChainAnswerIfComplete = jest.fn();

            //Act
            wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);

            //Assert
            expect(wrapper.vm.getQuestionChainAnswerIfComplete).toBeCalled();
        });

        test("should emit update:modelValue if returnedAnswer contains 'answer'", () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testQuestion = {};
            const testReturnedAnswer = "1|answer|DB10840|No";

            //Act
            wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);

            //Assert
            expect(wrapper.emitted()).toHaveProperty("update:modelValue");
            expect(wrapper.emitted()["update:modelValue"][0][0]).toMatchObject({
                answerResult: "DB10840",
            });
        });

        test("should NOT emit update:modelValue if no returnedAnswer", () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testQuestion = {};

            //Act
            wrapper.vm.handleAnswer(testQuestion);

            //Assert
            expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
        });

        test("should NOT emit update:modelValue if returnedAnswer contains 'nextQuestion'", () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testQuestion = {};
            const testReturnedAnswer = "1|nextQuestion|DB10840|No";

            //Act
            wrapper.vm.handleAnswer(testQuestion, testReturnedAnswer);

            //Assert
            expect(wrapper.emitted()).not.toHaveProperty("update:modelValue");
        });
    });

    describe("method getQuestionChainAnswerIfComplete...", () => {
        test("should return false if no returned answer", () => {
            //Arrange
            const { wrapper } = setupMocks({});

            //Act
            const result = wrapper.vm.getQuestionChainAnswerIfComplete();

            //Assert
            expect(result).toBeFalsy();
        });

        test("should set the answerSelected to match the answered one", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testReturnedAnswer = "1|answer|DB10840|No";
            await wrapper.setData({
                questionData: [
                    {
                        questionSequence: 1,
                        questionText: "Question here?",
                        answers: [
                            {
                                answerResult: "DB09410",
                                answerText: "Yes",
                                nextQuestionSequence: null,
                            },
                            {
                                answerResult: "DB10840",
                                answerText: "No",
                                nextQuestionSequence: null,
                            },
                        ],
                    },
                ],
            });

            //Act
            wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

            //Assert
            expect(wrapper.vm.questions[0].answerSelected).toBe("1|answer|DB10840|No");
        });

        test("should remove answers of questions after the answered one", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testReturnedAnswer = "1|answer|DB10840|No";
            await wrapper.setData({
                questionData: [
                    {
                        questionSequence: 1,
                        questionText: "Question here?",
                        answers: [
                            {
                                answerResult: "DB09410",
                                answerText: "Yes",
                                nextQuestionSequence: null,
                            },
                            {
                                answerResult: "DB10840",
                                answerText: "No",
                                nextQuestionSequence: null,
                            },
                        ],
                    },
                    {
                        questionSequence: 2,
                        questionText: "Question 2",
                        answers: [
                            {
                                answerResult: "2-yes",
                                answerText: "Yes",
                                nextQuestionSequence: null,
                            },
                            {
                                answerResult: "2-no",
                                answerText: "No",
                                nextQuestionSequence: null,
                            },
                        ],
                        answerSelected: "previously selected answer",
                    },
                ],
            });

            //Act
            wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

            //Assert
            expect(wrapper.vm.questions[1].answerSelected).toBeUndefined;
        });

        test("should return false if returnedAnswer is a nextQuestion (not a final answer)", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testReturnedAnswer = "1|nextQuestion|DB10840|No";

            //Act
            const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

            //Assert
            expect(result).toBeFalsy();
        });

        test("should trigger scroll to .current-question if returnedAnswer is a nextQuestion (not a final answer)", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testReturnedAnswer = "1|nextQuestion|DB10840|No";

            //Act
            wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

            await nextTick();

            //Assert
            expect(Element.prototype.scrollIntoView).toHaveBeenCalled();
        });

        test("should return answer object if returnedAnswer is a final matching answer", async () => {
            //Arrange
            const { wrapper } = setupMocks({});
            const testReturnedAnswer = "1|answer|DB10840|No";
            await wrapper.setData({
                questions: [
                    {
                        questionSequence: 1,
                        questionText: "Question here?",
                        answers: [
                            {
                                answerResult: "DB09410",
                                answerText: "Yes",
                                nextQuestionSequence: null,
                            },
                            {
                                answerResult: "DB10840",
                                answerText: "No",
                                nextQuestionSequence: null,
                            },
                        ],
                    },
                ],
            });
            await wrapper.setProps({ index: 0 });

            //Act
            const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

            //Assert
            expect(result).toMatchObject({
                answerResult: "DB10840",
                answeredQuestions: [
                    { questionNum: 1, questionText: "Question here?", selectedAnswerText: "No" },
                    {
                        questionNum: 1,
                        questionText: "Does only your center sliding piece need to be replaced?",
                        selectedAnswerText: "No",
                    },
                ],
                index: 0,
            });
        });
    });
});

function setupMocks({
    questionDataProp = [
        {
            questionSequence: 1,
            questionText: "Does only your center sliding piece need to be replaced?",
            answers: [
                {
                    answerResult: "DB09410",
                    answerText: "Yes",
                    nextQuestionSequence: null,
                },
                {
                    answerResult: "DB10840",
                    answerText: "No",
                    nextQuestionSequence: null,
                },
            ],
        },
    ],
}) {
    Element.prototype.scrollIntoView = jest.fn();

    const mountOptions = getMountOptions({});
    mountOptions.propsData = {
        questionData: questionDataProp,
    };
    mountOptions["attachTo"] = document.body;

    const wrapper = shallowMount(questionChain, mountOptions);

    return { wrapper };
}
