/* global describe: true, test:true, expect:true */
import { playlists as playlistsReducer, initialState } from '~/reducers/playlists';
import {
	GET_PLAYLISTS,
	GET_PLAYLISTS_SUCCESS,
	GET_PLAYLISTS_ERROR,
	GET_PLAYLIST_CONTENT,
	GET_PLAYLIST_CONTENT_SUCCESS,
	GET_PLAYLIST_CONTENT_ERROR,
	LOGOUT_SUCCESS,
	CREATE_DYNAMIC_PLAYLIST_SUCCESS,
	GET_DYNAMIC_PLAYLISTS_SUCCESS,
	UPLOAD_ITEM_STARTED,
	UPLOAD_ITEMS_SUCCESS,
	UPLOAD_ITEMS_ERROR,
	PLAYLIST_PROCESSING_STARTED,
	PLAYLIST_PROCESSING_DONE,
	UPLOAD_SUCCESS,
	UPLOAD_ALL_CANCELLED,
} from '~/store/actionTypes';

import Factory from 'helper/factories/api';

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

	test('CASE 2: should return state with meta set to loading when type is GET_PLAYLISTS', () => {
		const playlists = [{ id: 1 }, { id: 2 }];
		const expectedState = { ...initialState, meta: { ...initialState.meta, loading: false } };
		const stateResult = playlistsReducer(initialState, {
			type: GET_PLAYLISTS, payload: { playlists },
		});
		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 3a: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
		const playlists = Factory.buildList('Playlist', 6);
		const googleId = 'someone@gmail.com';
		const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
		const statePlaylists = playlists.map((item) => ({ ...item, slides: [{ url: 'url' }] }));
		const originalState = {
			...initialState, playlists: statePlaylists, dynamicPlaylists,
		};
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLISTS_SUCCESS, payload: { playlists },
		});
		expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
			name: expect.any(String),
			googleId: expect.any(String),
			status: expect.any(String),
			slides: expect.any(Array),
			dynamicPlaylistName: expect.any(String),
			lastSynced: expect.any(String),
		})]));
	});

	test('CASE 3b: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
		const playlists = Factory.buildList('Playlist', 1);
		const googleId = 'someone@gmail.com';
		const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
		const originalState = { ...initialState, dynamicPlaylists };
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLISTS_SUCCESS, payload: { playlists },
		});
		expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
			name: expect.any(String),
			googleId: expect.any(String),
			status: expect.any(String),
			dynamicPlaylistName: expect.any(String),
			lastSynced: expect.any(String),
			googleCollectionType: expect.any(String),
		})]));
	});

	test('CASE 3c: should return state with playlist content merged with dynamic playlist when type is GET_PLAYLISTS_SUCCESS', () => {
		const playlists = Factory.buildList('Playlist', 1);
		const googleId = 'someone@gmail.com';
		const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
		const statePlaylists = playlists.map((item) => ({ ...item, slides: [{ url: 'url' }] }));
		const originalState = {
			...initialState, playlists: statePlaylists, dynamicPlaylists,
		};
		const count = Math.floor((Math.random() * 500) + 1);
		const thumbs = [0, 1, 2].map(item => ({ src: `https://loremflickr.com/1024/768/cats?asdf=${item}`, rotation: 0, orientation: 1 }));
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLISTS_SUCCESS, payload: { playlists: [{ ...playlists[0], count, thumbs }] },
		});
		// The count and thumbs properties should be overridden by the new playlists data
		expect(stateResult.playlists[0].count).toEqual(count);
		expect(stateResult.playlists[0].thumbs).toEqual(thumbs);
	});

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

	test('CASE 5: should return state with meta set to loading when type is GET_PLAYLIST_CONTENT', () => {
		const playlists = [
			{ id: 1 },
			{ id: 2 },
		];
		const originalState = { ...initialState, playlists };
		const payload = { playlistId: 1 };
		const expectedState = {
			...initialState,
			playlists: [{
				id: 1,
				meta: { error: '', loading: true },
			},
			{ id: 2 }],
			meta: { error: '', loading: false, uploading: false },
		};
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLIST_CONTENT, payload,
		});
		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 6a: should return state with playlist content set when type is GET_PLAYLIST_CONTENT_SUCCESS', () => {
		const playlists = [
			{ id: 1 },
		];
		const originalState = { ...initialState, playlists };
		const payload = {
			playlistId: 1,
			playlist: { name: 'PL one', slides: [] },
			offset: 0,
		};
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLIST_CONTENT_SUCCESS, payload,
		});
		expect(stateResult.playlists[0]).toHaveProperty('name', payload.playlist.name);
		expect(stateResult.playlists[0]).toHaveProperty('slides');
		// expect(stateResult.playlists[0]).toHaveProperty('thumbs');
	});

	test('CASE 6b: GET_PLAYLIST_CONTENT_SUCCESS should combine playlist slides if offset is > 0', () => {
		const initialSlides = ['a', 'b', 'c'];
		const nextSlides = ['d', 'e', 'f'];
		const playlists = [
			{
				id: 1, slides: initialSlides, pictureCount: 6, offset: 3,
			},
		];
		const originalState = { ...initialState, playlists };
		const payload = {
			playlistId: 1,
			playlist: {
				name: 'PL one',
				slides: nextSlides,
				offset: 5,
				pictureCount: 6,
			},
			startOffset: 3,
			endOffset: 6,
		};
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLIST_CONTENT_SUCCESS, payload,
		});
		expect(stateResult.playlists[0]).toHaveProperty('slides', [...initialSlides, ...nextSlides]);
	});

	test('CASE 7: should return state error when type is GET_PLAYLIST_CONTENT_ERROR', () => {
		const playlists = [
			{ id: 1, meta: { error: '', loading: true } },
			{ id: 2, meta: { error: '', loading: false } },
		];
		const originalState = { ...initialState, playlists };
		// console.log({ originalState: JSON.stringify(originalState) });
		const error = new Error('getPlaylistError');
		const payload = {
			playlistId: 1,
			error,
		};
		const expectedState = {
			...initialState,
			playlists: [{
				id: 1,
				meta: { error, loading: false },
			},
			{ id: 2, meta: { error: '', loading: false } }],
			meta: { error: '', loading: false, uploading: false },
		};
		const stateResult = playlistsReducer(originalState, {
			type: GET_PLAYLIST_CONTENT_ERROR, payload,
		});
		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 9: should empty the state on LOGOUT_SUCCESS', () => {
		const existingState = [{ id: 1 }, { id: 2 }];
		expect(playlistsReducer(existingState, { type: LOGOUT_SUCCESS }))
			.toEqual(initialState);
	});

	test('CASE 10: should current state on CREATE_DYNAMIC_PLAYLIST_SUCCESS', () => {
		const existingState = [{ id: 1 }, { id: 2 }];
		expect(playlistsReducer(existingState, { type: CREATE_DYNAMIC_PLAYLIST_SUCCESS }))
			.toEqual(existingState);
	});

	test('CASE 11: should return state with dynamicPlaylist set when type is GET_DYNAMIC_PLAYLISTS_SUCCESS', () => {
		const playlists = Factory.buildList('Playlist', 6);
		const googleId = 'someone@gmail.com';
		const dynamicPlaylists = playlists.map(playlist => Factory.build('GoogleDynamicPlaylist', { playlistId: playlist.id, googleId }));
		const originalState = { ...initialState, playlists };

		const stateResult = playlistsReducer(originalState, {
			type: GET_DYNAMIC_PLAYLISTS_SUCCESS, payload: { google: dynamicPlaylists },
		});
		expect(stateResult.playlists).toEqual(expect.arrayContaining([expect.objectContaining({
			name: expect.any(String),
			googleId: expect.any(String),
			status: expect.any(String),
			dynamicPlaylistName: expect.any(String),
			lastSynced: expect.any(String),
		})]));

		expect(stateResult.dynamicPlaylists).toEqual(dynamicPlaylists);
	});
	test('CASE 12: should return state with upload state set when type is UPLOAD_ITEM_STARTED', () => {
		const expectedState = { ...initialState, meta: { ...initialState.meta, uploading: true } };
		const stateResult = playlistsReducer(initialState, {
			type: UPLOAD_ITEM_STARTED,
		});
		expect(stateResult).toEqual(expectedState);
	});
	test('CASE 13: should return state with upload state set when type is UPLOAD_ITEMS_SUCCESS or UPLOAD_ITEMS_ERROR', () => {
		const expectedState = { ...initialState, meta: { ...initialState.meta, uploading: false } };
		const stateResult = playlistsReducer(initialState, {
			type: UPLOAD_ITEMS_SUCCESS,
		});
		expect(stateResult).toEqual(expectedState);

		const expectedState2 = { ...initialState, meta: { ...initialState.meta, uploading: false } };
		const stateResult2 = playlistsReducer(initialState, {
			type: UPLOAD_ITEMS_ERROR,
		});
		expect(stateResult2).toEqual(expectedState2);
	});

	test('CASE 14: should return state with trackerId set when type is PLAYLIST_PROCESSING_STARTED', () => {
		const playlists = [
			{ id: 1, meta: { error: '', loading: true } },
			{ id: 2, meta: { error: '', loading: false } },
			{ id: 3, meta: { error: '', loading: true } },
		];
		const originalState = { ...initialState, playlists };


		const playlistsWithTracker = [
			{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
			{ id: 2, meta: { error: '', loading: false } },
			{ id: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f', meta: { error: '', loading: true } },
		];

		const expectedState = { ...originalState, playlists: playlistsWithTracker };

		const stateResult = playlistsReducer(originalState, {
			type: PLAYLIST_PROCESSING_STARTED,
			payload: {
				data: [
					{ receiver: '1', trackerId: 'a74d2e06f17e2893017431375b416b76' },
					{ receiver: '3', trackerId: '5b0e992791ed43ca79928eed54ca0b4f' },
				],
			},
		});

		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 15: should return state without trackerId set when type is PLAYLIST_PROCESSING_DONE', () => {
		const playlists = [
			{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
			{ id: 2, meta: { error: '', loading: false } },
			{ id: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f', meta: { error: '', loading: true } },
		];
		const originalState = { ...initialState, playlists };


		const playlistsWithTracker = [
			{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', loading: true } },
			{ id: 2, meta: { error: '', loading: false } },
			{ id: 3, meta: { error: '', loading: true } },
		];

		const expectedState = { ...originalState, playlists: playlistsWithTracker };

		const stateResult = playlistsReducer(originalState, {
			type: PLAYLIST_PROCESSING_DONE,
			payload: {
				playlistId: 3, trackerId: '5b0e992791ed43ca79928eed54ca0b4f',
			},
		});

		expect(stateResult).toEqual(expectedState);
	});

	test('CASE 16: should return state with meta.uploading set to false when type is UPLOAD_SUCCESS', () => {
		const playlists = [
			{ id: 1, meta: { error: '', uploading: true } },
			{ id: 2, meta: { error: '', uploading: false } },
			{ id: 3, meta: { error: '', uploading: true } },
		];
		const originalState = { ...initialState, playlists };
		const stateResult = playlistsReducer(originalState, {
			type: UPLOAD_SUCCESS,
		});

		stateResult.playlists.forEach((item) => {
			expect(item.meta).toHaveProperty('uploading', false);
		});
	});

	test('CASE 17: should return state with no trackerId and meta.uploading set to false when type is UPLOAD_ITEMS_ERROR or UPLOAD_ALL_CANCELLED', () => {
		const playlists = [
			{ id: 1, trackerId: 'a74d2e06f17e2893017431375b416b76', meta: { error: '', uploading: true } },
			{ id: 2, meta: { error: '', uploading: false } },
			{ id: 3, meta: { error: '', uploading: true } },
		];
		const originalState = { ...initialState, playlists };
		const stateResult = playlistsReducer(originalState, {
			type: UPLOAD_ALL_CANCELLED,
		});

		stateResult.playlists.forEach((item) => {
			expect(item.meta).toHaveProperty('uploading', false);
			expect(item).not.toHaveProperty('trackerId');
		});
	});
});
