import expect from 'expect';

import createTestState from 'mtest/helpers/createTestState';
import { makeFakeChannel } from 'mtest/fetchMocks/channel';

import {
  getChannelDetails,
  getChannelsByGame,
  doesChannelDataNeedsReinitForGame,
  areAllChannelsLoadedForGame,
} from 'mweb/common/selectors/data/channels';
import { ALL_CHANNELS } from 'mweb/common/reducers/data/channels';

describe('channels data selectors', () => {
  describe('getChannelDetails', () => {
    const channelDetails = makeFakeChannel();

    it('returns details for a loaded channel', () => {
      const state = createTestState({
        data: {
          channels: {
            channelDetails: {
              [channelDetails.name]: channelDetails,
            },
          },
        },
      });

      expect(getChannelDetails(state, channelDetails.name)).toEqual(
        channelDetails,
      );
    });

    it('returns undefined for non-loaded channel', () => {
      const state = createTestState();

      expect(getChannelDetails(state, channelDetails.name)).toEqual(undefined);
    });
  });

  describe('getChannelsByGame', () => {
    describe('ALL_CHANNELS', () => {
      const channel1 = makeFakeChannel({ viewerCount: 7, name: 'channel1' });
      const channel2 = makeFakeChannel({ viewerCount: 77, name: 'channel2' });
      const channelDetails = {
        [channel1.name]: channel1,
        [channel2.name]: channel2,
      };

      it('returns channels sorted by viewerCount descending when an ALL_CHANNELS page has been loaded', () => {
        const state = createTestState({
          data: {
            channels: {
              channelDetails: { ...channelDetails },
              channelsByGameLoadStatus: {
                [ALL_CHANNELS]: {
                  pagesLoaded: 1,
                },
              },
            },
          },
        });
        expect(getChannelsByGame(state, ALL_CHANNELS)).toEqual([
          channel2,
          channel1,
        ]);
      });

      it('returns channels sorted by viewerCount descending when an ALL_CHANNELS page has been loaded, respecting page size', () => {
        const state = createTestState({
          data: {
            channels: {
              channelDetails: { ...channelDetails },
              channelsByGameLoadStatus: {
                [ALL_CHANNELS]: {
                  pagesLoaded: 1,
                },
              },
            },
          },
        });
        expect(getChannelsByGame(state, ALL_CHANNELS, 1)).toEqual([channel2]);
      });

      it('returns empty list when an ALL_CHANNELS page has not been loaded', () => {
        const state = createTestState({
          data: {
            channels: {
              channelDetails: { ...channelDetails },
            },
          },
        });
        expect(getChannelsByGame(state, ALL_CHANNELS)).toEqual([]);
      });
    });

    describe('individual game', () => {
      it('returns channels sorted by viewerCount filtered for the target game', () => {
        const gameName = 'game';
        const channel1 = makeFakeChannel({
          viewerCount: 3,
          game: gameName,
          name: 'channel1',
        });
        const channel2 = makeFakeChannel({ game: 'other', name: 'channel2' });
        const channel3 = makeFakeChannel({
          viewerCount: 123,
          game: gameName,
          name: 'channel3',
        });
        const state = createTestState({
          data: {
            channels: {
              channelDetails: {
                [channel1.name]: channel1,
                [channel2.name]: channel2,
                [channel3.name]: channel3,
              },
            },
          },
        });
        expect(getChannelsByGame(state, gameName)).toEqual([
          channel3,
          channel1,
        ]);
      });
    });
  });

  describe('doesChannelDataNeedsReinitForGame', () => {
    it('returns true when there is no load status data for game', () => {
      const state = createTestState();
      expect(doesChannelDataNeedsReinitForGame(state, 'game')).toEqual(true);
    });

    it('returns true when there is a load status but there are no channels for this game', () => {
      const gameName = 'game';
      const state = createTestState({
        data: {
          channels: {
            channelsByGameLoadStatus: {
              [gameName]: {},
            },
          },
        },
      });
      expect(doesChannelDataNeedsReinitForGame(state, gameName)).toEqual(true);
    });

    it('returns true when there is a load status and channels for this game but last init time is stale', () => {
      const gameName = 'game';
      const channel = makeFakeChannel({ game: gameName });
      const state = createTestState({
        data: {
          channels: {
            channelDetails: {
              [channel.name]: channel,
            },
            channelsByGameLoadStatus: {
              [gameName]: {
                lastInitTime: 0,
              },
            },
          },
        },
      });
      expect(doesChannelDataNeedsReinitForGame(state, gameName)).toEqual(true);
    });

    it('returns false when there is a load status and channels for this game and last init time is fresh', () => {
      const gameName = 'game';
      const channel = makeFakeChannel({ game: gameName });
      const state = createTestState({
        data: {
          channels: {
            channelDetails: {
              [channel.name]: channel,
            },
            channelsByGameLoadStatus: {
              [gameName]: {
                lastInitTime: new Date().valueOf(),
              },
            },
          },
        },
      });
      expect(doesChannelDataNeedsReinitForGame(state, gameName)).toEqual(false);
    });
  });

  describe('areAllChannelsLoadedForGame', () => {
    it('returns false when there is a non-null lastChannelCursor', () => {
      const gameName = 'game';
      const state = createTestState({
        data: {
          channels: {
            channelsByGameLoadStatus: {
              [gameName]: {
                lastChannelCursor: 'abc',
              },
            },
          },
        },
      });
      expect(areAllChannelsLoadedForGame(state, gameName)).toEqual(false);
    });

    it('returns false when there is a null lastChannelCursor', () => {
      const gameName = 'game';
      const state = createTestState({
        data: {
          channels: {
            channelsByGameLoadStatus: {
              [gameName]: {
                lastChannelCursor: null,
              },
            },
          },
        },
      });
      expect(areAllChannelsLoadedForGame(state, gameName)).toEqual(true);
    });
  });
});
