import * as React from 'react';
import { MockConnectIframe } from './MockConnectIframe';
import { MockConnectHost } from './MockConnectHost';
import { mockIframeExtension } from './MockIframeExtension';
import { ConnectIframeDefinitions, ConnectIframe } from '../ConnectIframe';
import { MockConnectIframeProvider } from './MockConnectIframeProvider';
import { analytics } from '../../../adaptors/analytics/AnalyticsAdaptor';
import IFrameLifecycleEventManager from '../IFrameLifecycleEventManager';

import { AnalyticsCategories, AnalyticsActions } from '../../../adaptors/analytics/AnalyticsConstants';

jest.useFakeTimers();
jest.mock('../../../adaptors/analytics/AnalyticsAdaptor', () => {
    const { mockAnalytics } = require('./MockAnalyticsAdaptor');
    return { analytics: mockAnalytics };
});

describe('IframeLifecycleEventManager', () => {
    let iframeLifecycleEventManager:IFrameLifecycleEventManager;
    const props:ConnectIframeDefinitions.Props = {
        connectHost: new MockConnectHost(),
        appKey: 'appKey',
        moduleKey: 'moduleKey',
        url: 'url',
        width: 'width',
        height: 'height',
        options: {},
        connectIframeProvider: new MockConnectIframeProvider()
    };
    const mockConnectIframe:ConnectIframe = new MockConnectIframe(props);

    beforeEach(() => {
        jest.clearAllTimers();
        if (iframeLifecycleEventManager) {
          iframeLifecycleEventManager.reset();
        }
        iframeLifecycleEventManager = new IFrameLifecycleEventManager(mockConnectIframe);
    });

    describe('#constructor', () => {
        const onIframeEstablished =
            mockConnectIframe.props.connectHost.onIframeEstablished;
        const onIframeUnload =
            mockConnectIframe.props.connectHost.onIframeUnload;
        const handleIframeLoadingStarted =
            mockConnectIframe.props.connectIframeProvider.handleIframeLoadingStarted;
        const handleIframeLoadTimeout =
            mockConnectIframe.props.connectIframeProvider.handleIframeLoadTimeout;

        it('registers host callbacks', () => {
            expect(onIframeEstablished).toHaveBeenCalledTimes(1);
            expect(onIframeUnload).toHaveBeenCalledTimes(1);
            expect(handleIframeLoadingStarted).toHaveBeenCalledTimes(1);
        });

        it('triggers a timeout and invokes handlers if iframe doesn\'t load', () => {
            expect(setTimeout.mock.calls.length).toBe(1);
            expect(setTimeout.mock.calls[0][1]).toBe(12000);
            jest.runAllTimers();
            expect(handleIframeLoadTimeout).toHaveBeenCalledTimes(1);
            expect(handleIframeLoadTimeout).toHaveBeenCalledWith(
                'appKey',
                expect.anything()
            );
        });

        it('fires an analytics event on iframe timeout', () => {
            jest.runAllTimers();
            expect(analytics.trigger).toHaveBeenCalledTimes(1);
            expect(analytics.trigger).toHaveBeenCalledWith(
                AnalyticsCategories.iframe,
                AnalyticsActions.timeout,
                'appKey',
                expect.anything()
            );
        });
    });

    describe('#iframeEstablishedCallback', () => {
        const handleIframeLoadingComplete =
            mockConnectIframe.props.connectIframeProvider.handleIframeLoadingComplete;
        const offIframeEstablished =
            mockConnectIframe.props.connectHost.offIframeEstablished;
        const handleIframeLoadTimeout =
            mockConnectIframe.props.connectIframeProvider.handleIframeLoadTimeout;
        const iframeEstablishedCallback =
            mockConnectIframe.iframeEstablishedCallback;

        beforeEach(() => {
            iframeLifecycleEventManager.iframeEstablishedCallback(mockIframeExtension);
        });

        it('invokes the callback in the ConnectIframe', () => {
            expect(iframeEstablishedCallback).toHaveBeenCalledTimes(1);
        });

        it('invokes the registered callbacka', () => {
            expect(handleIframeLoadingComplete).toHaveBeenCalledTimes(1);
            expect(handleIframeLoadingComplete).toHaveBeenCalledWith(mockIframeExtension.extension.addon_key);
        });

        it('fires an analytics event', () => {
            expect(analytics.trigger).toHaveBeenCalledTimes(1);
            expect(analytics.trigger).toHaveBeenCalledWith(
                AnalyticsCategories.iframe,
                AnalyticsActions.established,
                mockIframeExtension.extension.addon_key,
                expect.anything()
            );
        });

        it('clears the timer', () => {
            jest.runAllTimers();
            expect(handleIframeLoadTimeout).not.toHaveBeenCalled();
        });
    });

    describe('#iframeUnloadCallback', () => {
        const handleIframeUnload =
            mockConnectIframe.props.connectIframeProvider.handleIframeUnload;

        beforeEach(() => {
            iframeLifecycleEventManager.iframeUnloadCallback(mockIframeExtension);
        });

        it('invokes the registered callbacka', () => {
            expect(handleIframeUnload).toHaveBeenCalledTimes(1);
            expect(handleIframeUnload).toHaveBeenCalledWith(mockIframeExtension.extension.id);
        });

        it('fires an analytics event', () => {
            expect(analytics.trigger).toHaveBeenCalledTimes(1);
            expect(analytics.trigger).toHaveBeenCalledWith(
                AnalyticsCategories.iframe,
                AnalyticsActions.close,
                mockIframeExtension.extension.id,
                expect.anything()
            );
        });
    });
});