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

import createTestStore from 'mtest/helpers/createTestStore';
import expectToReturnType from 'mtest/helpers/expectToReturnType';
import {
  GAMES_GQL_LAST_CURSOR,
  PARSED_GAMES_PAYLOAD,
  PARSED_GAMES_PAGE_2_PAYLOAD,
  mockGames,
  mockGamesPage2,
  mockGames404,
} from 'mtest/fetchMocks/games';

import {
  GAMES_DATA_PAGE_LOADED_ACTION_TYPE,
  GAMES_DATA_PAGE_FAILED_ACTION_TYPE,
  gamesDataGetPage,
  gamesDataFetchPage,
  gamesDataReinitialize,
  gamesDataLoadPage,
  GAME_DIRECTORY_CACHE_TTL,
} from 'mweb/common/actions/data/games';

describe('gamesData actions', () => {
  afterEach(() => {
    expect(fetchMock.done()).toEqual(true);
    fetchMock.restore();
  });

  describe('gamesDataGetPage', () => {
    it('reinitializes when there are no games even when lastInitTime is fresh', () => {
      const store = createTestStore({
        data: {
          games: {
            gamesLoadStatus: {
              lastInitTime: new Date().valueOf(),
            },
          },
        },
      });
      mockGames();

      return store.dispatch(gamesDataGetPage()).then(() => {
        const actions = store.getActions();
        expect(actions.shift()).toEqual(gamesDataReinitialize());
        expect(actions.shift()).toEqual(
          gamesDataLoadPage(PARSED_GAMES_PAYLOAD),
        );
      });
    });

    it('reinitializes when there are games but lastInitTime is stale', () => {
      const store = createTestStore({
        data: {
          games: {
            gameDetails: {
              fakeGame: {},
            },
            gamesLoadStatus: {
              lastInitTime: new Date().valueOf() - 2 * GAME_DIRECTORY_CACHE_TTL,
            },
          },
        },
      });
      mockGames();

      return store.dispatch(gamesDataGetPage()).then(() => {
        const actions = store.getActions();
        expect(actions.shift()).toEqual(gamesDataReinitialize());
        expect(actions.shift()).toEqual(
          gamesDataLoadPage(PARSED_GAMES_PAYLOAD),
        );
      });
    });

    it('does not request more games if it has some, lastInitTime is fresh, and one page opt is passed', () => {
      const store = createTestStore({
        data: {
          games: {
            gameDetails: {
              fakeGame: {},
            },
            gamesLoadStatus: {
              lastInitTime: new Date().valueOf(),
            },
          },
        },
      });

      return store
        .dispatch(gamesDataGetPage({ isOnePageEnough: true }))
        .then(() => {
          expect(store.getActions().length).toEqual(0);
        });
    });

    it('does not request more games when there are games and lastGameCursor is blank', () => {
      const store = createTestStore({
        data: {
          games: {
            gameDetails: {
              fakeGame: {},
            },
            gamesLoadStatus: {
              lastInitTime: new Date().valueOf(),
              lastGameCursor: null,
            },
          },
        },
      });

      return store.dispatch(gamesDataGetPage()).then(() => {
        expect(store.getActions().length).toEqual(0);
      });
    });

    it('loads next page when there are more games and lastInitTime is fresh', () => {
      const store = createTestStore({
        data: {
          games: {
            gameDetails: {
              fakeGame: {},
            },
            gamesLoadStatus: {
              lastInitTime: new Date().valueOf(),
              lastGameCursor: GAMES_GQL_LAST_CURSOR,
            },
          },
        },
      });
      mockGamesPage2();

      return store.dispatch(gamesDataGetPage()).then(() => {
        const actions = store.getActions();
        expect(actions.shift()).toEqual(
          gamesDataLoadPage(PARSED_GAMES_PAGE_2_PAYLOAD),
        );
      });
    });
  });

  describe('gamesDataFetchPage', () => {
    it('loads fetched data', () => {
      const store = createTestStore();
      mockGames();

      return store.dispatch(gamesDataFetchPage(null)).then(() => {
        const actions = store.getActions();
        expect(actions.shift()).toEqual(
          gamesDataLoadPage(PARSED_GAMES_PAYLOAD),
        );
      });
    });

    it('signals an loading error on 404 from API', () => {
      const store = createTestStore();
      mockGames404();

      return store.dispatch(gamesDataFetchPage(null)).then(() => {
        const actions = store.getActions();
        expect(actions.shift().type).toEqual(
          GAMES_DATA_PAGE_FAILED_ACTION_TYPE,
        );
      });
    });
  });

  describe('gamesDataLoadPage', () => {
    expectToReturnType(gamesDataLoadPage, GAMES_DATA_PAGE_LOADED_ACTION_TYPE);
  });
});
