import expect from 'expect';

import { expectEqualWithoutSpadeBaseTimeAndLocation } from 'mtest/helpers/trackingSelectors';
import createTestState from 'mtest/helpers/createTestState';
import { makeFakeGame } from 'mtest/fetchMocks/games';

import { RootState } from 'mweb/common/reducers/root';
import { Location } from 'mweb/common/reducers/app';
import { ChannelOnlineStatus } from 'mweb/common/reducers/data/channels';
import { VideoType } from 'mweb/common/reducers/data/baseVideoDetails';
import {
  getBasePageViewSpadeData,
  getGameDirectoryViewSpadeData,
  getChannelDirectoryViewSpadeData,
  getChannelPageViewSpadeData,
  getVODPageViewSpadeData,
  getUpsellPageViewSpadeData,
  getPageViewSpadeData,
  getChannelProfilePageViewSpadeData,
  getChatEmbedPageViewSpadeData,
  getProfileMetricsSpadeData,
} from 'mweb/common/selectors/tracking/pageview';

describe('pageview selectors', () => {
  interface PageViewTestCase {
    location: Location;
    selector: Function;
    stateSeed?: DeepPartial<RootState>;
    expectedData: Object;
  }

  const PAGE_VIEW_TEST_CASES: PageViewTestCase[] = [
    {
      // tested by getSpadeDataWithTimeAndLocation
      location: Location.DirectoryMainGame,
      selector: getGameDirectoryViewSpadeData,
      expectedData: {},
    },
    {
      location: Location.DirectoryGame,
      selector: getChannelDirectoryViewSpadeData,
      stateSeed: {
        pages: {
          channelDirectory: {
            currentGameAlias: 'afterlife',
          },
        },
      },
      expectedData: {
        game: 'afterlife',
      },
    },
    {
      location: Location.DirectoryGame,
      selector: getChannelDirectoryViewSpadeData,
      stateSeed: {
        data: {
          games: {
            gameNameLookup: {
              afterlife: 'Afterlife',
            },
            gameDetails: {
              Afterlife: makeFakeGame({ name: 'Afterlife' }),
            },
          },
        },
        pages: {
          channelDirectory: {
            currentGameAlias: 'afterlife',
          },
        },
      },
      expectedData: {
        game: 'Afterlife',
      },
    },
    {
      location: Location.Channel,
      selector: getChannelPageViewSpadeData,
      stateSeed: {
        pages: {
          channelViewer: {
            currentChannel: 'food',
          },
        },
        data: {
          channels: {
            channelDetails: {
              food: {
                name: 'food',
                id: '123',
                game: 'Creative',
                onlineStatus: ChannelOnlineStatus.Online,
              },
            },
          },
        },
      },
      expectedData: {
        channel: 'food',
        channel_id: 123,
        game: 'Creative',
        player: 'embed',
        is_live: true,
      },
    },
    {
      location: Location.ChannelProfile,
      selector: getChannelProfilePageViewSpadeData,
      stateSeed: {
        pages: {
          channelProfile: {
            currentChannel: 'bigandy',
          },
        },
        data: {
          channels: {
            channelDetails: {
              bigandy: {
                name: 'bigandy',
                id: '123',
              },
            },
          },
        },
      },
      expectedData: {
        channel: 'bigandy',
        channel_id: 123,
      },
    },
    {
      location: Location.ChatEmbed,
      selector: getChatEmbedPageViewSpadeData,
      stateSeed: {
        pages: {
          chatEmbed: {
            currentChannel: 'food',
          },
        },
        data: {
          channels: {
            channelDetails: {
              food: {
                name: 'food',
                id: '123',
              },
            },
          },
        },
      },
      expectedData: {
        channel: 'food',
        channel_id: 123,
      },
    },
    {
      location: Location.VOD,
      selector: getVODPageViewSpadeData,
      stateSeed: {
        pages: {
          vodViewer: {
            currentVODid: '124',
          },
        },
        data: {
          vods: {
            vodDetails: {
              ['124']: {
                id: '124',
                channel: 'twitch',
                game: 'Creative',
                videoType: VideoType.Highlight,
              },
            },
          },
          channels: {
            channelDetails: {
              ['twitch']: {
                name: 'twitch',
                id: '123',
              },
            },
          },
        },
      },
      expectedData: {
        vod_id: 'v124',
        vod_type: VideoType.Highlight,
        channel: 'twitch',
        channel_id: 123,
        player: 'embed',
        game: 'Creative',
      },
    },
    {
      // tested by getSpadeDataWithTimeAndLocation
      location: Location.Upsell,
      selector: getUpsellPageViewSpadeData,
      expectedData: {},
    },
  ];

  PAGE_VIEW_TEST_CASES.forEach(
    ({ location, selector, stateSeed, expectedData }) => {
      const state = createTestState({ ...stateSeed, app: { location } });
      describe(`for location ${location}`, () => {
        it('generates the proper event data from the target selector', () => {
          expectEqualWithoutSpadeBaseTimeAndLocation(
            selector(state),
            expectedData,
          );
        });

        it(`getPageViewSpadeData uses selector ${selector.name}`, () => {
          expectEqualWithoutSpadeBaseTimeAndLocation(
            getPageViewSpadeData(state, document.referrer),
            expectedData,
          );
        });
      });
    },
  );

  describe('getChannelPageViewSpadeData is_live', () => {
    interface ChannelIsLiveTestCase {
      name: string;
      is_live: boolean;
      stateSeed: DeepPartial<RootState>;
    }

    const CHANNEL_IS_LIVE_PAGE_VIEW_TEST_CASES: ChannelIsLiveTestCase[] = [
      {
        name: 'live channel',
        is_live: true,
        stateSeed: {
          pages: {
            channelViewer: {
              currentChannel: 'food',
            },
          },
          data: {
            channels: {
              channelDetails: {
                food: {
                  game: 'Creative',
                  onlineStatus: ChannelOnlineStatus.Online,
                },
              },
            },
          },
        },
      },
      {
        name: 'offline channel',
        is_live: false,
        stateSeed: {
          pages: {
            channelViewer: {
              currentChannel: 'food',
            },
          },
          data: {
            channels: {
              channelDetails: {
                food: {
                  game: 'Creative',
                  onlineStatus: ChannelOnlineStatus.Offline,
                },
              },
            },
          },
        },
      },
      {
        name: 'unknown channel',
        is_live: false,
        stateSeed: {
          pages: {
            channelViewer: {
              currentChannel: 'food',
            },
          },
          data: {
            channels: {
              channelDetails: {
                food: {
                  game: 'Creative',
                  onlineStatus: ChannelOnlineStatus.Unknown,
                },
              },
            },
          },
        },
      },
      {
        name: 'hosted channel',
        is_live: true,
        stateSeed: {
          pages: {
            channelViewer: {
              currentChannel: 'food',
            },
          },
          data: {
            channels: {
              channelDetails: {
                food: {
                  game: 'Creative',
                  onlineStatus: ChannelOnlineStatus.Online,
                  hostedChannel: 'eggplant',
                },
              },
            },
          },
        },
      },
    ];

    CHANNEL_IS_LIVE_PAGE_VIEW_TEST_CASES.forEach(
      ({ name, stateSeed, is_live }) =>
        it(`is right for ${name} with is_live set to ${is_live}`, () => {
          const state = createTestState(stateSeed);
          expect(
            getChannelPageViewSpadeData(state, document.referrer).is_live,
          ).toEqual(is_live);
        }),
    );
  });
});

describe('getBasePageViewSpadeData referrer_url', () => {
  interface BaseReferrerTestCase {
    referrer: string;
    isInternal: boolean;
  }

  const BASE_REFERRER_PAGE_VIEW_TEST_CASES: BaseReferrerTestCase[] = [
    {
      referrer: 'http://www.twitch.tv',
      isInternal: false,
    },
    {
      referrer: 'http://m.twitch.tv',
      isInternal: true,
    },
    {
      referrer: 'http://www.google.com',
      isInternal: false,
    },
    {
      referrer: 'https://google.com?s=m.twitch.tv',
      isInternal: false,
    },
    {
      referrer: 'http://www.m.twitch.tv',
      isInternal: true,
    },
    {
      referrer: 'https://clips.twitch.tv',
      isInternal: false,
    },
    {
      referrer: 'http://branch.m.twitch.tv',
      isInternal: true,
    },
    {
      referrer: 'http://localhost.m.twitch.tv:3003/',
      isInternal: true,
    },
  ];

  BASE_REFERRER_PAGE_VIEW_TEST_CASES.forEach(({ referrer, isInternal }) =>
    it(`is ${isInternal ? 'not' : ''} set for ${referrer}`, () => {
      const state = createTestState();
      expect(getBasePageViewSpadeData(state, referrer).referrer_url).toEqual(
        isInternal ? undefined : referrer,
      );
    }),
  );
});

describe('getProfileMetricsSpadeData', () => {
  it('generates the correct data when there is stuff', () => {
    const channel = 'monsterweasel';
    const state = createTestState({
      pages: {
        channelProfile: {
          currentChannel: channel,
        },
      },
      data: {
        channels: {
          channelDetails: {
            [channel]: {
              onlineStatus: ChannelOnlineStatus.Offline,
            },
          },
        },
        vods: {
          vodDetails: {
            vod1: {
              channel: channel,
              videoType: VideoType.Archive,
              date: 0,
            },
            vod2: {
              channel: channel,
              videoType: VideoType.Archive,
              date: 1,
            },
            vod3: {
              channel: channel,
              videoType: VideoType.Archive,
              date: 2,
            },
            vod4: {
              channel: channel,
              videoType: VideoType.Highlight,
              date: 0,
            },
            vod5: {
              channel: 'evilferret',
              videoType: VideoType.Archive,
              date: 0,
            },
            vod6: {
              channel: channel,
              videoType: VideoType.PastPremiere,
              date: 0,
            },
            vod7: {
              channel: channel,
              videoType: VideoType.Upload,
              date: 0,
            },
            vod8: {
              channel: channel,
              videoType: VideoType.Upload,
              date: 0,
            },
          },
        },
        clips: {
          clipDetails: {
            clip1: {
              channel,
              viewCount: 1,
              date: new Date().valueOf(),
            },
            clip2: {
              channel,
              viewCount: 2,
              date: new Date().valueOf(),
            },
            tooOldClip: {
              channel,
              viewCount: 3,
              date: 0,
            },
          },
        },
      },
    });

    expectEqualWithoutSpadeBaseTimeAndLocation(
      getProfileMetricsSpadeData(state),
      {
        archive_count: 3,
        clip_count: 2,
        highlight_count: 1,
        premiere_count: 1,
        upload_count: 2,
        is_live: false,
        top_content: VideoType.Archive,
        info_card_content: VideoType.Highlight,
      },
    );
  });

  it('generates the correct data when there is no stuff', () => {
    const channel = 'uglyduckling';
    const state = createTestState({
      pages: {
        channelProfile: {
          currentChannel: channel,
        },
      },
      data: {
        channels: {
          channelDetails: {
            [channel]: {
              onlineStatus: ChannelOnlineStatus.Offline,
            },
          },
        },
      },
    });

    expectEqualWithoutSpadeBaseTimeAndLocation(
      getProfileMetricsSpadeData(state),
      {
        archive_count: 0,
        clip_count: 0,
        highlight_count: 0,
        premiere_count: 0,
        upload_count: 0,
        is_live: false,
        top_content: undefined,
        info_card_content: undefined,
      },
    );
  });
});
