import { Alert } from 'react-native';
import { delay, put, race, select, take, takeLatest, actionChannel, throttle, fork, cancel } from 'redux-saga/effects';

import EventEmitter from '../lib/methods/helpers/events';
import Navigation from '../lib/navigation/appNavigation';
import * as types from '../actions/actionsTypes';
import { removedRoom } from '../actions/room';
import log, { events, logEvent } from '../lib/methods/helpers/log';
import I18n from '../i18n';
import { showErrorAlert } from '../lib/methods/helpers/info';
import { LISTENER } from '../containers/Toast';
import { leaveRoom, deleteRoom, leaveTeam, deleteTeam, forwardLivechat, emitTyping } from '../lib/services/restApi';
import getMoreMessages from '../lib/methods/getMoreMessages';
import { getMessageById } from '../lib/database/services/Message';

function* watchHistoryRequests() {
	const requestChan = yield actionChannel(types.ROOM.HISTORY_REQUEST);
	while (true) {
		const { rid, t, tmid, loaderId } = yield take(requestChan);

		const loaderItem = yield getMessageById(loaderId);
		if (loaderItem) {
			try {
				yield getMoreMessages({ rid, t, tmid, loaderItem });
			} catch (e) {
				log(e);
			} finally {
				yield put({ type: types.ROOM.HISTORY_FINISHED, loaderId });
			}
		}
	}
}

let inactiveTypingTask = null;

const clearUserTyping = function* clearUserTyping({ rid, status }) {
	try {
		if (!status) {
			yield emitTyping(rid, false);
			if (inactiveTypingTask) {
				yield cancel(inactiveTypingTask);
			}
		}
	} catch (e) {
		log(e);
	}
};

const clearInactiveTyping = function* clearInactiveTyping({ rid }) {
	yield delay(5000);
	yield clearUserTyping({ rid, status: false });
};

const watchUserTyping = function* watchUserTyping({ rid, status, args }) {
	try {
		if (status) {
			yield emitTyping(rid, status, args);
			if (inactiveTypingTask) {
				yield cancel(inactiveTypingTask);
			}
			inactiveTypingTask = yield fork(clearInactiveTyping, { rid });
		}
	} catch (e) {
		log(e);
	}
};

const handleRemovedRoom = function* handleRemovedRoom(roomType, actionType) {
	const isMasterDetail = yield select(state => state.app.isMasterDetail);
	Navigation.popToTop(isMasterDetail);

	if (actionType === 'leave') {
		EventEmitter.emit(LISTENER, {
			message: roomType === 'team' ? I18n.t('Left_The_Team_Successfully') : I18n.t('Left_The_Room_Successfully')
		});
	}
	if (actionType === 'delete') {
		EventEmitter.emit(LISTENER, {
			message: roomType === 'team' ? I18n.t('Deleted_The_Team_Successfully') : I18n.t('Deleted_The_Room_Successfully')
		});
	}

	// types.ROOM.REMOVE is triggered by `subscriptions-changed` with `removed` arg
	const { timeout } = yield race({
		deleteFinished: take(types.ROOM.REMOVED),
		timeout: delay(3000)
	});
	if (timeout) {
		put(removedRoom());
	}
};

const handleLeaveRoom = function* handleLeaveRoom({ room, roomType, selected }) {
	logEvent(events.RA_LEAVE);
	try {
		let result = {};

		if (roomType === 'channel') {
			result = yield leaveRoom(room.rid, room.t);
		} else if (roomType === 'team') {
			result = yield leaveTeam({ teamId: room.teamId, ...(selected && { rooms: selected }) });
		}

		if (result?.success) {
			yield handleRemovedRoom(roomType, 'leave');
		}
	} catch (e) {
		logEvent(events.RA_LEAVE_F);
		if (e.data && e.data.errorType === 'error-you-are-last-owner') {
			Alert.alert(I18n.t('Oops'), I18n.t(e.data.errorType));
		} else if (e?.data?.error === 'last-owner-can-not-be-removed') {
			Alert.alert(I18n.t('Oops'), I18n.t(e.data.error));
		} else {
			Alert.alert(I18n.t('Oops'), I18n.t('There_was_an_error_while_action', { action: I18n.t('leaving_room') }));
		}
	}
};

const handleDeleteRoom = function* handleDeleteRoom({ room, roomType, selected }) {
	logEvent(events.RI_EDIT_DELETE);
	try {
		let result = {};

		if (roomType === 'channel') {
			result = yield deleteRoom(room.rid || room._id, room.t);
		} else if (roomType === 'team') {
			result = yield deleteTeam({ teamId: room.teamId, ...(selected && { roomsToRemove: selected }) });
		}

		if (result?.success) {
			yield handleRemovedRoom(roomType, 'delete');
		}
	} catch (e) {
		logEvent(events.RI_EDIT_DELETE_F);
		Alert.alert(
			I18n.t('Oops'),
			I18n.t('There_was_an_error_while_action', {
				action: roomType === 'team' ? I18n.t('deleting_team') : I18n.t('deleting_room')
			})
		);
	}
};

const handleForwardRoom = function* handleForwardRoom({ transferData }) {
	try {
		const result = yield forwardLivechat(transferData);
		if (result === true) {
			const isMasterDetail = yield select(state => state.app.isMasterDetail);
			if (isMasterDetail) {
				Navigation.navigate('DrawerNavigator');
			} else {
				Navigation.navigate('RoomsListView');
			}
		} else {
			showErrorAlert(I18n.t('No_available_agents_to_transfer'), I18n.t('Oops'));
		}
	} catch (e) {
		showErrorAlert(e.reason, I18n.t('Oops'));
	}
};

const root = function* root() {
	yield takeLatest(types.ROOM.USER_TYPING, clearUserTyping);
	yield throttle(3000, types.ROOM.USER_TYPING, watchUserTyping);
	yield takeLatest(types.ROOM.LEAVE, handleLeaveRoom);
	yield takeLatest(types.ROOM.DELETE, handleDeleteRoom);
	yield takeLatest(types.ROOM.FORWARD, handleForwardRoom);
	yield watchHistoryRequests();
};
export default root;
