import { MessageComponent } from "@boldpenguin/sdk-types";
import { newSpecPage } from "@stencil/core/testing";
import { BpSdkMessageContainer } from "./bp-sdk-message-container";
const fakeStore = {
    application: {
        form: {
            messages: [
                {
                    id: 'testMessage',
                    component: MessageComponent.Application,
                    metadata: {},
                },
            ],
        },
    },
};
const setupPage = async () => {
    return await newSpecPage({
        html: '<bp-sdk-message-container></bp-sdk-message-container>',
        components: [BpSdkMessageContainer],
    });
};
const setupInstance = (page, messages) => {
    const instance = page.rootInstance;
    instance.storeUnsubscribe = jest.fn();
    instance.messages = messages || [];
    return instance;
};
const mockMessage = {
    id: 'message-id',
    tenant_id: 'message-tenant-id',
    owner_id: 'message-owner-id',
    target: 'Your application is taken over by an operator',
    application_form_id: 'message-app-form-id',
    active: true,
    component: MessageComponent.Application,
    metadata: {},
};
describe('bp-sdk-message-container', () => {
    describe('renders', () => {
        it('external', async () => {
            const whenDefinedMock = jest.spyOn(customElements, 'whenDefined').mockResolvedValueOnce({});
            const page = await setupPage();
            setupInstance(page, [mockMessage]);
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-message').length).toBe(0);
            whenDefinedMock.mockRestore();
        });
        it('nothing when there are no messages', async () => {
            const page = await setupPage();
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-message').length).toBe(0);
        });
        it('when there are are messages', async () => {
            const page = await setupPage();
            setupInstance(page, [mockMessage]);
            await page.waitForChanges();
            expect(page.body.querySelectorAll('bp-sdk-message').length).toBe(1);
        });
    });
    describe('state.lastMessage', () => {
        it('gets set when there is one message', async () => {
            const page = await setupPage();
            const instance = setupInstance(page, [mockMessage]);
            await page.waitForChanges();
            expect(instance.lastMessage).toEqual(mockMessage);
        });
        it('gets set to the last element when there are multiple messages', async () => {
            const page = await setupPage();
            const instance = setupInstance(page, [mockMessage, Object.assign(Object.assign({}, mockMessage), { id: 'second-message' })]);
            await page.waitForChanges();
            expect(instance.lastMessage.id).toEqual('second-message');
        });
        it('updates when a message gets added', async () => {
            const page = await setupPage();
            const instance = setupInstance(page, [mockMessage]);
            await page.waitForChanges();
            instance.messages = [...instance.messages, Object.assign(Object.assign({}, mockMessage), { id: 'second-message' })];
            await page.waitForChanges();
            expect(instance.lastMessage.id).toEqual('second-message');
        });
    });
    describe('disconnectedCallback', () => {
        it('should unsubscribe from the redux store', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.disconnectedCallback();
            expect(instance.storeUnsubscribe).toHaveBeenCalledTimes(1);
        });
    });
    describe('mapStateToProps', () => {
        it('returns messages from the store', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const result = instance.mapStateToProps(fakeStore);
            expect(result.messages).toEqual(fakeStore.application.form.messages);
        });
    });
    describe('handleSubscriptions', () => {
        it('calls unsubscribe if subscribed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(unsubscribe).toHaveBeenCalled();
        });
        it('overwrites an existing subscribe function', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toEqual(unsubscribe);
            expect(instance.storeUnsubscribe).toBeDefined();
        });
        it('subscribes if not subscribed', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.storeUnsubscribe = null;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toBeNull();
        });
        it('subscribes updates mapStateToProps if already has storeUnsubscribe', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            const unsubscribe = jest.fn();
            instance.storeUnsubscribe = unsubscribe;
            instance.handleSubscriptions();
            expect(instance.storeUnsubscribe).not.toEqual(unsubscribe);
        });
    });
    describe('connectedCallback', () => {
        it('makes expected call if root available', async () => {
            const page = await setupPage();
            const instance = setupInstance(page);
            instance.handleSubscriptions = jest.fn();
            jest.spyOn(instance.el, 'querySelector').mockImplementationOnce(() => ({
                componentOnReady: () => Promise.resolve(true),
            }));
            instance.connectedCallback();
            expect(instance.handleSubscriptions).toBeCalledTimes(1);
            await page.waitForChanges();
            expect(instance.handleSubscriptions).toBeCalledTimes(2);
        });
    });
});
