require('jsdom-global')();

import * as React from 'react';
import { Provider } from 'react-intl-redux';
import { mount } from 'enzyme';
import expect from 'expect';
import fetchMock from 'fetch-mock';
import { MemoryRouter } from 'react-router-dom';
import { Location } from 'history';

import { GAME_2, mockGamesPage3 } from 'mtest/fetchMocks/games';
import {
  mockChannelsAllGames,
  mockChannelsNoStreams,
} from 'mtest/fetchMocks/channels';
import { mockChannel, CHANNEL } from 'mtest/fetchMocks/channel';
import { mockVOD, VOD } from 'mtest/fetchMocks/vods';
import { EVENT_ID, mockEvent } from 'mtest/fetchMocks/event';
import TwitchPlayerMock from 'mtest/helpers/twitchPlayerMock';

import configureStore from 'mweb/common/stores/configureStore';
import Router from 'mweb/common/router';
import GameDirectory from 'mweb/common/containers/gameDirectory';
import { ChannelDirectory } from 'mweb/common/containers/channelDirectory';
import ChannelViewer from 'mweb/common/containers/channelViewer';
import ChannelProfile from 'mweb/common/containers/channelProfile';
import VODViewer from 'mweb/common/containers/vodViewer';
import Upsell from 'mweb/common/containers/upsell';
import EventDetails from 'mweb/common/containers/eventDetails';
import { NotFound } from 'mweb/common/components/errors/notFound';
import {
  buildLandingPagePath,
  buildGameDirectoryPath,
  buildChannelDirectoryPathFromDecodedGame,
  buildChannelPath,
  buildVODPath,
  buildLegacyVODPath,
  buildChannelProfilePath,
  buildEventPath,
} from 'mweb/common/utils/pathBuilders';
import { ALL_CHANNELS } from 'mweb/common/reducers/data/channels';

describe('Router', () => {
  before(() => {
    window.Twitch = {
      Player: TwitchPlayerMock,
    };
  });

  after(() => {
    delete window.Twitch;
  });

  interface RouterTest {
    target: string;
    path: string;
    mock?: () => void;
    gameDirectory?: 1;
    channelDirectory?: 1;
    channelViewer?: 1;
    vodViewer?: 1;
    upsell?: 1;
    notFound?: 1;
    channelProfile?: 1;
    eventDetails?: 1;
  }

  const routerTests: RouterTest[] = [
    {
      target: 'game directory',
      path: buildLandingPagePath(),
      mock: mockGamesPage3,
      gameDirectory: 1,
    },
    {
      target: 'game directory',
      path: buildGameDirectoryPath(),
      mock: mockGamesPage3,
      gameDirectory: 1,
    },
    {
      target: 'channel directory',
      path: buildChannelDirectoryPathFromDecodedGame(ALL_CHANNELS),
      mock: mockChannelsAllGames,
      channelDirectory: 1,
    },
    {
      target: 'channel directory',
      path: buildChannelDirectoryPathFromDecodedGame(GAME_2.name),
      mock: mockChannelsNoStreams,
      channelDirectory: 1,
    },
    {
      target: 'vod viewer',
      path: buildLegacyVODPath(CHANNEL, VOD),
      mock: mockVOD,
      vodViewer: 1,
    },
    {
      target: 'vod viewer',
      path: buildVODPath(VOD),
      mock: mockVOD,
      vodViewer: 1,
    },
    {
      target: 'channel viewer',
      path: buildChannelPath(CHANNEL),
      mock: mockChannel,
      channelViewer: 1,
    },
    {
      target: 'channel profile',
      path: buildChannelProfilePath(CHANNEL),
      mock: mockChannel,
      channelProfile: 1,
    },
    {
      target: 'event details',
      path: buildEventPath(EVENT_ID),
      mock: mockEvent,
      eventDetails: 1,
    },

    {
      target: 'upsell',
      path: '/upsell/path',
      upsell: 1,
    },
    {
      target: 'upsell',
      path: '/longer/upsell/path',
      upsell: 1,
    },
    {
      target: 'not found',
      path: '/too/long/to/upsell',
      notFound: 1,
    },
  ];

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

  routerTests.map(test => {
    it(`renders ${test.target} on ${test.path}`, () => {
      if (test.mock) {
        test.mock();
      }

      const wrapper = mount(
        <Provider store={configureStore()}>
          <MemoryRouter initialEntries={[{ pathname: test.path } as Location]}>
            <Router />
          </MemoryRouter>
        </Provider>,
      );

      expect(wrapper.find(GameDirectory).length).toEqual(
        test.gameDirectory || 0,
      );
      expect(wrapper.find(ChannelDirectory).length).toEqual(
        test.channelDirectory || 0,
      );
      expect(wrapper.find(ChannelViewer).length).toEqual(
        test.channelViewer || 0,
      );
      expect(wrapper.find(ChannelProfile).length).toEqual(
        test.channelProfile || 0,
      );
      expect(wrapper.find(VODViewer).length).toEqual(test.vodViewer || 0);
      expect(wrapper.find(Upsell).length).toEqual(test.upsell || 0);
      expect(wrapper.find(NotFound).length).toEqual(test.notFound || 0);
      expect(wrapper.find(EventDetails).length).toEqual(test.eventDetails || 0);
    });
  });

  it('lowercases the channel name passed to the channel theater container', () => {
    mockChannel();
    const wrapper = mount(
      <Provider store={configureStore()}>
        <MemoryRouter initialEntries={['/monsterCat']}>
          <Router />
        </MemoryRouter>
      </Provider>,
    );
    expect(wrapper.find(ChannelViewer).prop('match').params.channel).toEqual(
      'monstercat',
    );
  });

  it('lowercases the channel name passed to the channel profile container', () => {
    mockChannel();
    const wrapper = mount(
      <Provider store={configureStore()}>
        <MemoryRouter initialEntries={['/monsterCat/profile']}>
          <Router />
        </MemoryRouter>
      </Provider>,
    );
    expect(wrapper.find(ChannelProfile).prop('match').params.channel).toEqual(
      'monstercat',
    );
  });
});
