/* global describe: true, test:true, expect:true */
import {
	friends as friendsReducer,
	initialState,
	initAddFriend,
	addFriend as addFriendReducer,
} from '~/reducers/friends';
import {
	GET_FRIENDS,
	GET_FRIENDS_SUCCESS,
	GET_FRIENDS_ERROR,
	UPDATE_SEEN_TIMESTAMP_SUCCESS,
	LOGOUT_SUCCESS,
	UPDATE_ADD_FRIEND,
	ACCEPT_FRIEND_INVITE_SUCCESS,
	ACCEPT_FRIEND_INVITE_ERROR,
	REJECT_FRIEND_INVITE_SUCCESS,
	REJECT_FRIEND_INVITE_ERROR,
	RESET_ADD_FRIEND_ERROR,
	RESET_ADD_FRIEND_PLAYLIST,
} from '~/store/actionTypes';

describe('friends reducer', () => {
	test('CASE 1: should return initial state', () => {
		expect(friendsReducer(undefined, { type: 'Default' }))
			.toEqual(initialState);
	});

	test('CASE 2: should return state with meta set to loading when type is GET_FRIENDS', () => {
		const expectedState = { ...initialState, meta: { ...initialState.meta, loading: true } };
		const stateResult = friendsReducer(initialState, {
			type: GET_FRIENDS, payload: {},
		});
		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 3: should return state with meta set to loading when type is GET_FRIENDS_SUCCESS', () => {
		const friends = [{ username: '1', activity: { timestamp: 0 } }, { username: '2', activity: { timestamp: 0 } }];
		const invites = [{ requester: '1' }, { requester: '2' }];
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, {
			type: GET_FRIENDS_SUCCESS, payload: { friends: { friends, invites } },
		});
		expect(stateResult.friends).toEqual([]);
		expect(stateResult.invites[0]).toHaveProperty('meta', meta);
	});

	test('CASE 4: should return state with error when type is GET_FRIENDS_ERROR', () => {
		const error = new Error('getFriendsError');
		const expectedState = { ...initialState, meta: { ...initialState.meta, error } };
		const stateResult = friendsReducer(initialState, {
			type: GET_FRIENDS_ERROR, payload: { error },
		});
		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 5: should return state when type is UPDATE_SEEN_TIMESTAMP_SUCCESS', () => {
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, { type: UPDATE_SEEN_TIMESTAMP_SUCCESS });
		expect(stateResult).toHaveProperty('meta', meta);
	});

	test('CASE 6: should return state with loading = false when type is ACCEPT_FRIEND_INVITE_SUCCESS', () => {
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, { type: ACCEPT_FRIEND_INVITE_SUCCESS });
		expect(stateResult).toHaveProperty('meta', meta);
	});

	test('CASE 7: should return state with loading = false when type is ACCEPT_FRIEND_INVITE_ERROR', () => {
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, { type: ACCEPT_FRIEND_INVITE_ERROR, payload: { error: '' } });
		expect(stateResult).toHaveProperty('meta', meta);
	});

	test('CASE 8: should return state with loading = false when type is REJECT_FRIEND_INVITE_SUCCESS', () => {
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, { type: REJECT_FRIEND_INVITE_SUCCESS });
		expect(stateResult).toHaveProperty('meta', meta);
	});

	test('CASE 9: should return state with loading = false when type is REJECT_FRIEND_INVITE_ERROR', () => {
		const meta = { loading: false, error: '' };
		const stateResult = friendsReducer(initialState, { type: REJECT_FRIEND_INVITE_ERROR, payload: { error: '' } });
		expect(stateResult).toHaveProperty('meta', meta);
	});

	test('CASE 10: should empty the state on LOGOUT_SUCCESS', () => {
		const existingState = {};
		expect(friendsReducer(existingState, { type: LOGOUT_SUCCESS }))
			.toEqual(initialState);
	});

	test('CASE 11: addFriend should return initial state', () => {
		expect(addFriendReducer(undefined, { type: 'Default' }))
			.toEqual(initAddFriend);
	});

	test('CASE 12: addFriend should return state when type is UPDATE_ADD_FRIEND', () => {
		const stateResult = friendsReducer(initAddFriend, {
			type: UPDATE_ADD_FRIEND,
			payload: {
				lookupKey: '',
				friendName: '',
				playlistId: -1,
				hasError: '',
				isNewPlaylist: 0,
				popCount: 2,
			},
		});
		expect(stateResult).toEqual(initAddFriend);
	});

	test('CASE 13: addFriend should update error state when type is UPDATE_ADD_FRIEND', (hasError = '') => {
		const {
			lookupKey,
			friendName,
			playlistId,
			isNewPlaylist,
		} = initAddFriend;
		const stateResult = friendsReducer(initAddFriend, {
			type: RESET_ADD_FRIEND_ERROR,
			payload: {
				lookupKey,
				friendName,
				playlistId,
				hasError,
				isNewPlaylist,
			},
		});
		expect(stateResult).toEqual(initAddFriend);
	});

	test('CASE 14: addFriend should update error state when type is RESET_ADD_FRIEND_ERROR', (hasError = '') => {
		const stateResult = friendsReducer(initAddFriend, {
			type: RESET_ADD_FRIEND_ERROR,
			payload: { hasError },
		});
		expect(stateResult).toEqual(initAddFriend);
	});

	test('CASE 15: addFriend should update error state when type is RESET_ADD_FRIEND_PLAYLIST', (isNewPlaylist = 0) => {
		const stateResult = friendsReducer(initAddFriend, {
			type: RESET_ADD_FRIEND_PLAYLIST,
			payload: { isNewPlaylist },
		});
		expect(stateResult).toEqual(initAddFriend);
	});

	test('CASE 16: Badge should be true when a new friend invite has been added to state GET_FRIENDS_SUCCESS', () => {
		const existingState = { ...initialState, invites: [{ requester: '1' }, { requester: '2' }] };
		const friends = {
			invites: [{ requester: '1' }, { requester: '3' }],
			friends: [{ username: '1', activity: { timestamp: 0 } }],
		};
		const stateResult = friendsReducer(existingState, {
			type: GET_FRIENDS_SUCCESS,
			payload: { friends },
		});
		expect(stateResult).toHaveProperty('isBadged', true);
	});

	test('CASE 17: Badge should be true when a new friend invite GET_FRIENDS_SUCCESS', () => {
		const existingState = { ...initialState, invites: [{ requester: '1' }, { requester: '2' }] };
		const friends = {
			invites: [{ requester: '1' }],
			friends: [{ username: '1', activity: { timestamp: 0 } }],
		};
		const stateResult = friendsReducer(existingState, {
			type: GET_FRIENDS_SUCCESS,
			payload: { friends },
		});
		expect(stateResult).toHaveProperty('isBadged', false);
	});

	test('CASE 18: Badge should be true when a friend gets a new activity', () => {
		const existingState = { ...initialState, invites: [], friends: [{ username: '1', activity: { timestamp: 1 } }] };
		const friends = {
			invites: [],
			friends: [{ username: '1', activity: { timestamp: 2 } }],
		};
		const stateResult = friendsReducer(existingState, {
			type: GET_FRIENDS_SUCCESS,
			payload: { friends },
		});
		expect(stateResult).toHaveProperty('isBadged', false);
	});
});
