import {
    handleAnyComponentFocus,
    handleButtonComponentFocus,
    handleInputComponentBlur,
} from "@/helpers/button-question-focus-helper";

describe("buttonQuestionFocusHelper", () => {
    let onButtonQuestionLostFocusCallbackOne = jest.fn();
    let onButtonQuestionLostFocusCallbackTwo = jest.fn();

    let focusOnInputInGroupOne;
    let blurFromInputInGroupOne;
    let focusOnInputInGroupTwo;
    let blurFromInputInGroupTwo;

    let focusOnNonRadioCheckboxElement;

    beforeEach(() => {
        onButtonQuestionLostFocusCallbackOne = jest.fn();
        onButtonQuestionLostFocusCallbackTwo = jest.fn();

        // Sanity check
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        focusOnInputInGroupOne = () => {
            handleButtonComponentFocus({
                groupName: "group1",
            });
        };

        blurFromInputInGroupOne = () => {
            handleInputComponentBlur({
                groupName: "group1",
                onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackOne,
            });
        };

        focusOnInputInGroupTwo = () => {
            handleButtonComponentFocus({
                groupName: "group2",
            });
        };

        blurFromInputInGroupTwo = () => {
            handleInputComponentBlur({
                groupName: "group2",
                onButtonQuestionLostFocusCallback: onButtonQuestionLostFocusCallbackTwo,
            });
        };

        focusOnNonRadioCheckboxElement = () => {
            handleAnyComponentFocus({
                target: {
                    type: "nonRadioCheckbox",
                },
            });
        };
    });

    test("focus on input => no callbacks were called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on input, then focus on input in same group => no callbacks are called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 1
        blurFromInputInGroupOne();
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on non-radio/checkbox, focus on input => no callbacks are called", () => {
        // focus on non-radio/checkbox
        focusOnNonRadioCheckboxElement();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on input in group 1, then focus on input in different group => callback for group 1 is called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in different group
        blurFromInputInGroupOne();
        focusOnInputInGroupTwo();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on input in group 1, focus on input in same group, then focus on input in different group => callback for group 1 is called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in same group
        blurFromInputInGroupOne();
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in different group
        blurFromInputInGroupOne();
        focusOnInputInGroupTwo();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on input in group 1, focus on non-radio/checkbox element => callback from group 1 is called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 2
        blurFromInputInGroupOne();
        focusOnNonRadioCheckboxElement();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();
    });

    test("focus on input in group 1, focus on input in group 2, focus on non-radio/checkbox element => both callbacks are called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 2
        blurFromInputInGroupOne();
        focusOnInputInGroupTwo();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0);

        // focus on non-radio/checkbox
        blurFromInputInGroupTwo();
        focusOnNonRadioCheckboxElement();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
    });

    test("focus on input in group 1, focus on input in group 2, focus on input in group 1 => both callbacks are called", () => {
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 2
        blurFromInputInGroupOne();
        focusOnInputInGroupTwo();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(0);

        // focus on input in group 1
        blurFromInputInGroupTwo();
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
    });

    test("go back and forth a lot => correct callbacks are called at the right time", () => {
        // Arrange/Act
        // focus on input in group 1
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).not.toHaveBeenCalled();
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 2
        blurFromInputInGroupOne();
        focusOnInputInGroupTwo();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).not.toHaveBeenCalled();

        // focus on input in group 1
        blurFromInputInGroupTwo();
        focusOnInputInGroupOne();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(1);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);

        // focus on non-radio/checkbox element
        blurFromInputInGroupOne();
        focusOnNonRadioCheckboxElement();

        // Assert
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);

        // focus on input in group 1
        focusOnInputInGroupOne();
        expect(onButtonQuestionLostFocusCallbackOne).toHaveBeenCalledTimes(2);
        expect(onButtonQuestionLostFocusCallbackTwo).toHaveBeenCalledTimes(1);
    });
});
