require('jsdom-global')();

import expect from 'expect';
import fetchMock from 'fetch-mock';

import ChatClientMock from 'mtest/chat/helpers/chatClientMock';
import {
  mockAllBadges,
  mockChannel2Badges,
  TEST_CHANNEL_ID,
  TEST_CHANNEL_ID_2,
} from 'mtest/chat/helpers/badgerFetchMocks';

import { BadgerService } from 'mweb/chat/badgerService';
import { ChatEvent } from 'mweb/chat/events/baseChatEvent';
// types have to be imported
import { WorkerMessage } from 'mweb/chat/chatService';
// objects have to be required in order to avoid hoisting above jsdom
const {
  ChatService,
  CHAT_WORKER_CONNECTED,
  CHAT_WORKER_CHANNEL_CHANGED,
} = require('mweb/chat/chatService');

describe('ChatService', () => {
  let chatService: typeof ChatService; // weird because of needing jsdom
  let chatClient: ChatClientMock;
  let badger: BadgerService;
  let polyfillURI: string;

  function importScripts(uri: string): void {
    polyfillURI = uri;
  }

  function postMessage(_event: ChatEvent): void {
    return;
  }

  beforeEach(() => {
    chatClient = new ChatClientMock();
    badger = new BadgerService();
    chatService = new ChatService(
      importScripts,
      postMessage,
      chatClient,
      badger,
    );
    mockAllBadges();
  });

  afterEach(() => {
    expect(fetchMock.done()).toEqual(true);
    fetchMock.restore();
  });

  describe('messageHandler', () => {
    const CONNECT_MESSAGE: WorkerMessage = {
      command: CHAT_WORKER_CONNECTED,
      payload: {
        channelName: 'voxel',
        channelID: TEST_CHANNEL_ID,
        polyfillURI: '//polyfill.sexy',
      },
    };

    it('connects on CHAT_WORKER_CONNECTED message', () => {
      expect(chatClient.connected).toEqual(false);

      expect(chatClient.connectedHandler).toNotExist();
      expect(chatClient.disconnectedHandler).toNotExist();
      expect(chatClient.reconnectHandler).toNotExist();

      expect(chatClient.hostingHandler).toNotExist();
      expect(chatClient.unhostHandler).toNotExist();

      expect(chatClient.chatHandler).toNotExist();
      expect(chatClient.actionHandler).toNotExist();
      expect(chatClient.timeoutHandler).toNotExist();
      expect(chatClient.banHandler).toNotExist();
      expect(chatClient.subscriptionHandler).toNotExist();
      expect(chatClient.resubscriptionHandler).toNotExist();

      return chatService.messageHandler({ data: CONNECT_MESSAGE }).then(() => {
        expect(chatService.channelName).toEqual(
          CONNECT_MESSAGE.payload.channelName,
        );
        expect(chatService.channelID).toEqual(
          CONNECT_MESSAGE.payload.channelID,
        );

        expect(chatClient.connected).toEqual(true);
        expect(chatClient.currentChannel).toEqual(
          CONNECT_MESSAGE.payload.channelName,
        );

        expect(chatClient.connectedHandler).toExist();
        expect(chatClient.disconnectedHandler).toExist();
        expect(chatClient.reconnectHandler).toExist();

        expect(chatClient.hostingHandler).toExist();
        expect(chatClient.unhostHandler).toExist();

        expect(chatClient.chatHandler).toExist();
        expect(chatClient.actionHandler).toExist();
        expect(chatClient.timeoutHandler).toExist();
        expect(chatClient.banHandler).toExist();
        expect(chatClient.subscriptionHandler).toExist();
        expect(chatClient.resubscriptionHandler).toExist();

        expect(badger.badges).toExist();
        /* tslint:disable-next-line:no-string-literal */
        expect(badger.badges['warcraft']).toExist();

        expect(polyfillURI).toEqual('//polyfill.sexy');
      });
    });

    it('changes chat channel on CHAT_WORKER_CHANNEL_CHANGED message', () => {
      mockChannel2Badges();
      const changeChannelMessage: WorkerMessage = {
        command: CHAT_WORKER_CHANNEL_CHANGED,
        payload: {
          channelName: 'monstercat',
          channelID: TEST_CHANNEL_ID_2,
        },
      };

      return chatService
        .messageHandler({ data: CONNECT_MESSAGE })
        .then(() => {
          expect(chatService.channelName).toEqual(
            CONNECT_MESSAGE.payload.channelName,
          );
          expect(chatService.channelID).toEqual(
            CONNECT_MESSAGE.payload.channelID,
          );

          expect(chatClient.currentChannel).toEqual(
            CONNECT_MESSAGE.payload.channelName,
          );

          return chatService.messageHandler({ data: changeChannelMessage });
        })
        .then(() => {
          expect(chatService.channelName).toEqual(
            changeChannelMessage.payload.channelName,
          );
          expect(chatService.channelID).toEqual(
            changeChannelMessage.payload.channelID,
          );

          expect(chatClient.currentChannel).toEqual(
            changeChannelMessage.payload.channelName,
          );
        });
    });
  });
});
