import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'helpers/test_constants';
import * as actions from 'ee/project_licenses/store/modules/list/actions';
import * as types from 'ee/project_licenses/store/modules/list/mutation_types';
import getInitialState from 'ee/project_licenses/store/modules/list/state';

import { FETCH_ERROR_MESSAGE } from 'ee/project_licenses/store/modules/list/constants';
import createFlash from '~/flash';

import mockLicensesResponse from './data/mock_licenses';

jest.mock('~/flash', () => jest.fn());

describe('Licenses actions', () => {
  const pageInfo = {
    page: 3,
    nextPage: 2,
    previousPage: 1,
    perPage: 20,
    total: 100,
    totalPages: 5,
  };

  const headers = {
    'X-Next-Page': pageInfo.nextPage,
    'X-Page': pageInfo.page,
    'X-Per-Page': pageInfo.perPage,
    'X-Prev-Page': pageInfo.previousPage,
    'X-Total': pageInfo.total,
    'X-Total-Pages': pageInfo.totalPages,
  };

  afterEach(() => {
    createFlash.mockClear();
  });

  describe('setLicensesEndpoint', () => {
    it('commits the SET_LICENSES_ENDPOINT mutation', () =>
      testAction(
        actions.setLicensesEndpoint,
        TEST_HOST,
        getInitialState(),
        [
          {
            type: types.SET_LICENSES_ENDPOINT,
            payload: TEST_HOST,
          },
        ],
        [],
      ));
  });

  describe('requestLicenses', () => {
    it('commits the REQUEST_LICENSES mutation', () =>
      testAction(
        actions.requestLicenses,
        undefined,
        getInitialState(),
        [
          {
            type: types.REQUEST_LICENSES,
          },
        ],
        [],
      ));
  });

  describe('receiveLicensesSuccess', () => {
    it('commits the RECEIVE_LICENSES_SUCCESS mutation', () =>
      testAction(
        actions.receiveLicensesSuccess,
        { headers, data: mockLicensesResponse },
        getInitialState(),
        [
          {
            type: types.RECEIVE_LICENSES_SUCCESS,
            payload: {
              licenses: mockLicensesResponse.licenses,
              reportInfo: mockLicensesResponse.report,
              pageInfo,
            },
          },
        ],
        [],
      ));
  });

  describe('receiveLicensesError', () => {
    it('commits the RECEIVE_LICENSES_ERROR mutation', () => {
      const error = { error: true };

      return testAction(
        actions.receiveLicensesError,
        error,
        getInitialState(),
        [
          {
            type: types.RECEIVE_LICENSES_ERROR,
          },
        ],
        [],
      ).then(() => {
        expect(createFlash).toHaveBeenCalledTimes(1);
        expect(createFlash).toHaveBeenCalledWith(FETCH_ERROR_MESSAGE);
      });
    });
  });

  describe('fetchLicenses', () => {
    let state;
    let mock;

    beforeEach(() => {
      state = getInitialState();
      state.endpoint = `${TEST_HOST}/licenses`;
      mock = new MockAdapter(axios);
    });

    afterEach(() => {
      mock.restore();
    });

    describe('when endpoint is empty', () => {
      beforeEach(() => {
        state.endpoint = '';
      });

      it('returns a rejected promise', () =>
        expect(actions.fetchLicenses({ state })).rejects.toEqual(
          new Error('No endpoint provided'),
        ));
    });

    describe('on success', () => {
      describe('given no params', () => {
        beforeEach(() => {
          state.pageInfo = { ...pageInfo };

          const paramsDefault = {
            page: state.pageInfo.page,
            per_page: 10,
          };

          mock
            .onGet(state.endpoint, { params: paramsDefault })
            .replyOnce(200, mockLicensesResponse, headers);
        });

        it('uses default params from state', () =>
          testAction(
            actions.fetchLicenses,
            undefined,
            state,
            [],
            [
              {
                type: 'requestLicenses',
              },
              {
                type: 'receiveLicensesSuccess',
                payload: expect.objectContaining({ data: mockLicensesResponse, headers }),
              },
            ],
          ));
      });

      describe('given params', () => {
        const paramsGiven = {
          page: 4,
        };

        const paramsSent = {
          ...paramsGiven,
          per_page: 10,
        };

        beforeEach(() => {
          mock
            .onGet(state.endpoint, { params: paramsSent })
            .replyOnce(200, mockLicensesResponse, headers);
        });

        it('overrides default params', () =>
          testAction(
            actions.fetchLicenses,
            paramsGiven,
            state,
            [],
            [
              {
                type: 'requestLicenses',
              },
              {
                type: 'receiveLicensesSuccess',
                payload: expect.objectContaining({ data: mockLicensesResponse, headers }),
              },
            ],
          ));
      });
    });

    describe('given a response error', () => {
      beforeEach(() => {
        mock.onGet(state.endpoint).replyOnce([500]);
      });

      it('dispatches the receiveLicensesError action and creates a flash', () =>
        testAction(
          actions.fetchLicenses,
          undefined,
          state,
          [],
          [
            {
              type: 'requestLicenses',
            },
            {
              type: 'receiveLicensesError',
              payload: expect.any(Error),
            },
          ],
        ));
    });
  });
});
