import { shallowMount } from '@vue/test-utils';
import crypto from 'crypto';
import { useForm } from 'vee-validate';
import { Modal } from 'bootstrap';
import modal from '@/digital-components/modal/modal.vue';

jest.mock('vee-validate', () => ({
    useForm: jest.fn()
}));

const mockValidate = (returnValue) => jest.fn(async () => Promise.resolve({ valid: returnValue }));
const mockMeta = (returnValue) => jest.fn(async () => Promise.resolve(returnValue));

const footerButtonText = 'Sample footer text here.';
const headerText = 'Sample header text here.';

global.crypto = crypto;

describe('modal.vue', () => {
    it('Should display modal header text when headerText is defined', async () => {
        // Arrange / Act
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });

        const wrapper = shallowMount(modal, {
            props: {
                headerText,
                footerButtonText
            },
            attachTo: document.body
        });

        // Assert
        expect(wrapper.html()).toEqual(expect.stringContaining(headerText));
    });

    it('Should display footer button text when footerButtonText is defined', async () => {
        // Arrange / Act
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText
            },
            attachTo: document.body
        });

        // Assert
        expect(wrapper.html()).toEqual(expect.stringContaining(footerButtonText));
    });

    it("Should emit 'footer-button-event' if the form is valid", async () => {
        // Arrange
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });

        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Act
        const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' });
        await buttonMain.trigger('click-event');

        // Assert
        expect(wrapper.emitted('footer-button-event')).toBeTruthy();
    });

    it("Should not emit 'footer-button-event' if the form is invalid", async () => {
        // Arrange
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: false,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(false)
        });
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Act
        const buttonMain = wrapper.findComponent({ ref: 'modalButtonMain' });
        await buttonMain.trigger('click-event');

        // Assert
        expect(wrapper.emitted('footer-button-event')).toBeFalsy();
    });

    it('Should have a disabled footer button when the form has not been touched', async () => {
        // Arrange / Act
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Assert
        expect(wrapper.vm.isFooterButtonDisabled).toBe(true);
    });

    it('Should have a disabled footer button when the form is invalid', async () => {
        // Arrange / Act
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Assert
        expect(wrapper.vm.isFooterButtonDisabled).toBe(true);
    });

    it("Should call bootstrap Modal method 'show' when calling 'openModal'", async () => {
        // Arrange
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });

        const showMock = jest.spyOn(Modal.prototype, 'show');
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Act
        wrapper.vm.openModal();

        // Assert
        expect(showMock).toHaveBeenCalled();
    });

    it("Should call bootstrap Modal method 'hide' when calling 'closeModal'", async () => {
        // Arrange
        const fakeMeta = {
            touched: true,
            dirty: true,
            valid: true,
            validated: true
        };

        useForm.mockReturnValue({
            meta: mockMeta(fakeMeta),
            validate: mockValidate(true)
        });
        const hideMock = jest.spyOn(Modal.prototype, 'hide');
        const wrapper = shallowMount(modal, {
            props: {
                footerButtonText,
                headerText
            },
            attachTo: document.body
        });

        // Act
        wrapper.vm.openModal();
        wrapper.vm.closeModal();

        // Assert
        expect(hideMock).toHaveBeenCalled();
    });
});
