import PushNotification from 'react-native-push-notification';
import _ from 'lodash';
import DeviceInfo from 'react-native-device-info';
import { Platform } from 'react-native';
import PushNotificationIOS from '@react-native-community/push-notification-ios';
import { store } from '~/store/store';
import { ToasterService } from 'nixplay-ui-kit';
import i18n from '~/locale/i18n';
import {
	SHOW_ACTIVITY,
	GET_FRIENDS,
	GET_FRIENDS_INVITES,
	GET_FRIEND_ACTIVITIES,
	RESET_NOTIFICATION,
	GET_PLAYLISTS,
	GET_DYNAMIC_PLAYLISTS,
	GET_COMMENTS,
	UPDATE_SHOW_NOTIFICATION,
	SHOW_FRIENDS_TAB_BADGE,
	SHARED_PLAYLIST_MEMBERS,
	NOTIFICATION_ITEM_RECEIVED,
	GET_SHARED_PLAYLIST_INVITES,
	UPLOAD_CANCEL_ALL_QUEUE,
	ADD_SHARED_PLAYLIST_NEW_AUDIENCE,
	SET_PHOTOS_TAB_BADGE,
	SET_LANGUAGE_SETTING,
	DISPLAY_LANGUAGE_CHANGED_POPUP,
} from '~/store/actionTypes';
import {
	EVENT_ITEM_UPLOADED,
	EVENT_PHOTO_RECEIVED,
	EVENT_NEW_REQUEST,
	EVENT_FRIEND_REQUEST_ACCEPTED,
	EVENT_FRIEND_COMMENT,
	NIX_EVENT,
	PAGE_FRIENDS_TAB,
	PAGE_PHOTOS_TAB,
	NIX_EVENT_DATA_UPDATE,
	NIX_DYNAMIC_PLAYLIST_UPDATED,
	EVENT_USER_SETTINGS_UPDATE,
	// NIX_CONTACTS,
	NIX_SHARED_PLAYLIST_UPDATED,
	ACTION_MEMBER_REMOVED,
	ACTION_INVITE_RECEIVED,
	ACTION_INVITE_ACCEPTED,
	ACTION_INVITE_REJECTED,
	ACTION_QUIT,
} from '~/store/notificationConstants';
import { localeToLanguageCode } from '~/lib/locale';

const info = {};
const refreshFriendEvents =
[
	EVENT_NEW_REQUEST,
	EVENT_FRIEND_REQUEST_ACCEPTED,
	EVENT_PHOTO_RECEIVED,
	EVENT_FRIEND_COMMENT,
];

const clearAll = () => {
	PushNotification.cancelAllLocalNotifications();
	PushNotification.setApplicationIconBadgeNumber(0);
};

const reloadFriendActivities = () => {
	// check if need to refresh currently opened friend activities
	const { friend } = store.getState().friendActivities;
	if (!_.isEmpty(friend)) {
		store.dispatch({
			type: GET_FRIEND_ACTIVITIES,
			payload: {
				friend,
				nextTimestamp: null,
				updateTimestamp: false,
			},
		});
	}
};

const getNotificationTitle = notification => {
	if (_.get(notification, 'title')) {
		return notification.title;
	}
	if (_.get(notification, 'alert.title')) {
		return notification.alert.title;
	}
	if (_.get(notification, 'aps.alert.title')) {
		return notification.aps.alert.title;
	}
	return '';
};

const getNotificationMessage = notification => {
	if (_.get(notification, 'message')) {
		return notification.message;
	}
	return '';
};

const showToast = (isToastShown, message) => {
	if (isToastShown && (Platform.OS === 'ios' || (Platform.OS === 'android' && Platform.Version >= 26))) {
		if (!_.isEmpty(message)) {
			ToasterService.toast({
				theme: 'dark',
				text: message,
				time: 2000,
			});
		}
	}
};

const onUpdateFriends = () => {
	// refresh friends if it's a refreshFriendEvent regardless of app state
	store.dispatch({ type: GET_FRIENDS });
	store.dispatch({ type: GET_FRIENDS_INVITES });
	reloadFriendActivities();
};

const onGetPayload = (notification) => {
	const bodyMsg = (_.isObject(notification.message)) ? notification.message.body : notification.message;
	if (_.isEmpty(bodyMsg)) return null;
	const userFullName = bodyMsg.replace(/(?: sent...*)/g, '');
	const itemString = bodyMsg.substr(userFullName.length);
	const strCount = itemString.replace(/\D/g, '');
	return { userFullName, count: strCount };
};

// This will extract out the nixObject from notification payload
function getNixObject(notification) {
	if (notification.nixObject) {
		return notification.nixObject;
	} else if (notification.payload) {
		return notification.payload.nixObject;
	} else if (notification.data && notification.data.nixObject) {
		return notification.data.nixObject;
	} else if (notification.data && notification.data.payload) {
		return notification.data.payload.nixObject;
	}
	return {};
}

function getEvent(notification) {
	if (_.has(notification, NIX_EVENT)) {
		return notification.nixEvent;
	} else if (_.has(notification, 'data.nixEvent')) {
		return notification.data.nixEvent;
	} else if (_.has(notification, 'data.payload.nixEvent')) {
		return notification.data.payload.nixEvent;
	}
	return null;
}

// Returns md5 associated with the notification
function getMD5(notification) {
	if (_.has(notification, 'md5')) {
		const { md5 } = notification;
		return md5;
	} else if (_.has(notification, 'data.md5')) {
		const { md5 } = notification.data;
		return md5;
	}
	return null;
}

const refreshDynamicPlaylists = () => {
	store.dispatch({ type: GET_DYNAMIC_PLAYLISTS });
	store.dispatch({ type: GET_PLAYLISTS });
};

const isSharedPlaylistUpdate = notification =>
	getNixObject(notification) === NIX_SHARED_PLAYLIST_UPDATED;

const getActionFromNotification = notification =>
	notification &&
	notification.data &&
	notification.data.payload &&
	notification.data.payload.details &&
	notification.data.payload.details.action;

const getPageFromAction = action => {
	switch (action) {
		case ACTION_INVITE_RECEIVED:
		case ACTION_INVITE_REJECTED:
		case ACTION_INVITE_ACCEPTED:
			return PAGE_PHOTOS_TAB;
		case ACTION_MEMBER_REMOVED:
		case ACTION_QUIT:
		default:
			return undefined;
	}
};

function handleBackground(notification, event) {
	/**
	 * Force showing of toast message in specific device that issue occur
	 * Known device: iPhone 6s+
	 */
	showToast(DeviceInfo.getDeviceId === 'iPhone8,2', getNotificationTitle(notification));
	onUpdateFriends();
	if (Platform.OS === 'android' && (_.has(notification, 'badge'))) {
		PushNotification.setApplicationIconBadgeNumber(parseInt(notification.badge, 0));
	}
	if (notification.userInteraction) {
		const action = getActionFromNotification(notification);
		const page = isSharedPlaylistUpdate(notification) ? getPageFromAction(action) : PAGE_FRIENDS_TAB;
		const notificationData = getNixObject(notification);
		const pageObj = page || {};
		const payload = _.isObject(notificationData) ? {
			data: notificationData,
			page: pageObj,
		} : {
			page: pageObj,
		};
		Object.assign(payload, { action });
		switch (event) {
			case NIX_EVENT_DATA_UPDATE: { // shared playlist notifications
				if (notification.data && notification.data.payload && notification.data.payload.details) {
					const { details } = notification.data.payload;
					const { target } = details;
					switch (action) {
						case ACTION_INVITE_ACCEPTED: {
							if (target) {
								const { playlistId, playlistName, friend } = target;
								Object.assign(payload, {
									page: 'Photos',
									params: {
										playlistId,
										playlistName,
										friend,
									},
								});
							}
							break;
						}
						case ACTION_MEMBER_REMOVED:
						case ACTION_INVITE_RECEIVED: {
							const { playlistId } = details;
							Object.assign(payload, {
								page: 'Photos',
								params: {
									playlistId,
								},
							});
							break;
						}
						default:
					}
				}
				break;
			}
			case EVENT_PHOTO_RECEIVED: { // friend activities photo received
				payload.page = 'Photos';
				payload.action = 'EVENT_PHOTO_RECEIVED';
				break;
			}
			default: {
				// this is not needed for now
			}
		}
		// redirection to page
		store.dispatch({
			type: SHOW_ACTIVITY,
			payload,
		});
	} else if (!notification.userInteraction && isSharedPlaylistUpdate(notification)) {
		const action = getActionFromNotification(notification);
		const page = getPageFromAction(action);
		const notificationData = getNixObject(notification);
		const payload = {
			...(_.isObject(notificationData) ? { data: notificationData } : {}),
			...(page ? { page } : {}),
		};

		store.dispatch({
			type: SHOW_ACTIVITY,
			payload,
		});
	} else if (!notification.userInteraction &&
		event === EVENT_USER_SETTINGS_UPDATE) {
		const key = (Platform.OS === 'ios') ? 'data.data.locale' : 'data.locale';
		const localeData = _.get(notification, key, 'en_US');
		const locale = localeToLanguageCode(localeData);
		if (i18n.locale !== locale) {
			store.dispatch({ type: DISPLAY_LANGUAGE_CHANGED_POPUP });
			_.defer(() => {
				store.dispatch({ type: SET_LANGUAGE_SETTING, payload: { locale } });
			});
		}
	}
}

function handleForeground(notification, event) {
	clearAll();
	store.dispatch({ type: RESET_NOTIFICATION });
	const notificationData = getNixObject(notification);
	const action = getActionFromNotification(notification);
	if (event === NIX_EVENT_DATA_UPDATE
		&& action === ACTION_INVITE_ACCEPTED
		&& notification.data
		&& notification.data.payload
		&& notification.data.payload.details
		&& notification.data.payload.details.target) {
		const { playlistId, playlistName, friend } = notification.data.payload.details.target;
		showToast(true, i18n.t('playlists.friendJoinedPlaylist', {
			friendName: friend.fullName || '',
			playlistName: playlistName || '',
		}));
		store.dispatch({
			type: ADD_SHARED_PLAYLIST_NEW_AUDIENCE,
			payload: { playlistId, playlistName, friend },
		});
		store.dispatch({ type: GET_PLAYLISTS });
		store.dispatch({ type: GET_SHARED_PLAYLIST_INVITES });
		store.dispatch({ type: SHARED_PLAYLIST_MEMBERS, payload: { playlistId } });
	} else if (event === EVENT_PHOTO_RECEIVED) {
		showToast(true, getNotificationTitle(notification));
		const { userFullName, count } = onGetPayload(notification);
		store.dispatch({
			type: NOTIFICATION_ITEM_RECEIVED,
			payload: { userFullName, keyToUpdate: 'timestamp', count },
		});
	} else if (event === EVENT_FRIEND_COMMENT) {
		showToast(true, getNotificationTitle(notification));
		const { friend, mediaViewer } = store.getState().friendActivities;
		const md5 = getMD5(notification);
		if (!_.isEmpty(md5) && !_.isEmpty(friend) && md5 === mediaViewer.md5) {
			// When active it will trigger to refresh the reducer
			store.dispatch({ type: GET_COMMENTS, payload: { md5, friendUsername: friend.username } });
		}
	} else if (event === EVENT_FRIEND_REQUEST_ACCEPTED) {
		showToast(true, getNotificationTitle(notification));
	} else if (event === EVENT_NEW_REQUEST) {
		showToast(true, getNotificationTitle(notification));
	} else if (event === NIX_EVENT_DATA_UPDATE && notificationData === NIX_DYNAMIC_PLAYLIST_UPDATED) {
		refreshDynamicPlaylists();
	} else if (event === NIX_EVENT_DATA_UPDATE && isSharedPlaylistUpdate(notification)) {
		showToast(true, getNotificationTitle(notification));
	} else if (event === EVENT_ITEM_UPLOADED) {
		// global update to all pages that has upload issues
		store.dispatch({ type: UPLOAD_CANCEL_ALL_QUEUE });
	} else if (event === EVENT_USER_SETTINGS_UPDATE) {
		const key = (Platform.OS === 'ios') ? 'data.data.locale' : 'data.locale';
		const localeData = _.get(notification, key, 'en_US');
		const locale = localeToLanguageCode(localeData);
		if (i18n.locale !== locale) {
			store.dispatch({ type: DISPLAY_LANGUAGE_CHANGED_POPUP });
			_.defer(() => {
				store.dispatch({ type: SET_LANGUAGE_SETTING, payload: { locale } });
			});
		}
	} else if (event === NIX_EVENT_DATA_UPDATE && getNixObject(notification) === 'like') {
		showToast(true, getNotificationMessage(notification));
	}
	if (event === NIX_EVENT_DATA_UPDATE &&
		(getActionFromNotification(notification) === ACTION_INVITE_REJECTED ||
		getActionFromNotification(notification) === ACTION_INVITE_ACCEPTED ||
		getActionFromNotification(notification) === ACTION_QUIT ||
		getNixObject(notification) === NIX_SHARED_PLAYLIST_UPDATED)) {
		store.dispatch({ type: SET_PHOTOS_TAB_BADGE, payload: { photosTab: true } });
		store.dispatch({ type: GET_PLAYLISTS });
		store.dispatch({ type: GET_SHARED_PLAYLIST_INVITES });
	}
	// // update friends everytime there's a new friend-related notification
	onUpdateFriends();
}

// New function for processing notification
const processNotification = (notification) => {
	store.dispatch({ type: UPDATE_SHOW_NOTIFICATION, payload: true });
	const event = getEvent(notification);
	if (_.isEmpty(event)) return;
	if (refreshFriendEvents.indexOf(event) > -1) {
		store.dispatch({ type: SHOW_FRIENDS_TAB_BADGE, payload: {} });
	}
	if (notification.foreground) {
		handleForeground(notification, event);
	} else {
		handleBackground(notification, event);
	}
};

/* istanbul ignore next */
const configure = () => {
	PushNotification.configure({

		onRegister(token) {
			info.key = token.token;
			store.dispatch({ type: RESET_NOTIFICATION });
		},

		onNotification(notification) {
			// console.log('notification ', notification);
			if (notification) {
				processNotification(notification);
			}
			notification.finish(PushNotificationIOS.FetchResult.NoData);
		},

		permissions: {
			alert: true,
			badge: true,
			sound: true,
		},
		senderID: '772716672707',
		popInitialNotification: true,
		requestPermissions: true,

	});
};

/* istanbul ignore next */
// const localNotification = ({
// 	message, title,
// }) => {
// 	PushNotification.localNotification({
// 		vibrate: true,
// 		vibration: 300,
// 		title,
// 		message,
// 		playSound: true,
// 		soundName: 'default',
// 	});
// };

export {
	configure,
	// localNotification,
	info,
	clearAll,
	processNotification, // local function
	getEvent, // local function
	getMD5, // local function
	onGetPayload, // local function
	getNixObject, // local function
};
