import { delay } from 'redux-saga';
import { call, put, takeEvery, takeLatest, select } from 'redux-saga/effects';
import * as _ from 'lodash';

import { actions as chatActions } from '../chat';
import { actions as StreamActions } from '../stream';
import { actions as batchProfileActions } from '../profiles';

import * as chatApi from '../../api/chat';

import { getUserCredentails } from './sagaSelector';
import { eventTracker } from '../../utils/EventTracker';

export function* getChats() {
  const { username, password } = yield select(getUserCredentails);
  try {
    const chats = yield call(chatApi.fetchChats, username, password);
    if (chats.length >= 0) {
      yield put({ type: chatActions.setChats, payload: chats });
      yield put({
        type: batchProfileActions.fetchProfiles,
        payload: { peerIDs: chats.map(chat => chat.peerId) },
      });
    }
  } catch (err) {
    console.log('Chats Saga Error: ', err);
  }
  yield put({ type: chatActions.setChatsLoading, payload: false });
}

export function* updateChats() {
  const { username, password } = yield select(getUserCredentails);
  try {
    const chats = yield call(chatApi.fetchChats, username, password);
    if (chats.length >= 0) {
      yield put({ type: chatActions.setChats, payload: chats });
      yield put({
        type: batchProfileActions.fetchProfiles,
        payload: { peerIDs: chats.map(chat => chat.peerId) },
      });
    }
  } catch (err) {
    console.log('Chats Saga Error: ', err);
  }
  yield delay(60 * 1000);
  yield put({ type: chatActions.updateChats });
}

export function* getChatDetail(action) {
  const { username, password } = yield select(getUserCredentails);
  const { peerID, subject, isFromOrder } = action.payload;
  try {
    const result = yield call(
      chatApi.fetchChatDetail,
      username,
      password,
      isFromOrder ? null : peerID,
      subject,
    );
    yield put({
      type: chatActions.setChatDetailLoading,
      payload: false,
    });
    yield put({
      type: chatActions.setChatDetail,
      payload: {
        chatDetails: result,
        peerID,
        subject,
      },
    });
  } catch (err) {
    console.log('ChatDetail Saga Error: ', err);
  }
}

export function* sendChat(action) {
  const { username, password } = yield select(getUserCredentails);
  const {
    peerID, message, localId, onSent, subject = '', orderType,
  } = action.payload;
  try {
    // Send message request to backend
    if (message !== '') {
      eventTracker.trackEvent('Chat-MessageSent');
    }
    const result = yield call(
      chatApi.sendChat,
      username,
      password,
      peerID,
      subject,
      message,
      orderType,
    );
    if (message !== '') {
      // If the message is successfully sent, then set the message info saved in local to success
      // and updates the state in the component to success
      eventTracker.trackEvent('Chat-MessageDelivered');
      yield put({ type: chatActions.updateLocalInfo, payload: { localId, result, success: _.get(result, 'success', true) } });
      yield put({ type: chatActions.fetchChats });
      if (onSent) {
        yield call(onSent, _.get(result, 'success', true));
      }
    }
  } catch (err) {
    if (message !== '') {
      // If the message is failed to sent, then set the message info saved in local to failure
      // and updates the state in the component to failure
      eventTracker.trackEvent('Chat-MessageFailed', { reason: err.reason });
      yield put({ type: chatActions.updateLocalInfo, payload: { localId, success: false } });
      if (onSent) {
        yield call(onSent, false);
      }
    }
  }
}

export function* sendNotification(peerID, orderId, orderType) {
  yield put({ type: StreamActions.sendNotification,
    payload: {
      verb: 'chat',
      type: 'sent',
      peerID,
      content: { body: 'You have received a message!', orderId, orderType },
    } });
}

export function* sendChatNotification(action) {
  const { peerID, message, subject: orderId, orderType: myOrderType } = action.payload;
  if (_.isEmpty(message)) {
    return;
  }

  let orderType = myOrderType === 'purchases' ? 'sales' : 'purchases';

  if (typeof peerID === 'string') {
    yield call(sendNotification, peerID, orderId, orderType);
  } else {
    for (let i = 0; i < peerID.length; i += 1) {
      yield call(sendNotification, peerID[i], orderId, orderType);
    }
  }
}

export function* setChatAsRead(action) {
  const { username, password } = yield select(getUserCredentails);
  const { peerID, subject, isFromOrder } = action.payload;
  try {
    yield call(
      chatApi.setChatAsRead,
      username,
      password,
      isFromOrder ? null : peerID,
      subject,
    );
  } catch (err) {
    console.log('Saga Error: Set Chat As Read Errors');
  }
}

export function* deleteChatConversation(action) {
  const { username, password } = yield select(getUserCredentails);
  const peerID = action.payload;
  try {
    yield call(
      chatApi.deleteChatConversation,
      username, password, peerID,
    );
    yield put({ type: chatActions.fetchChats });
  } catch (err) {
    console.log('Saga Error: Delete Chat Conversation');
  }
}

export default function* Chat() {
  yield takeEvery(chatActions.fetchChats, getChats);
  yield takeEvery(chatActions.updateChats, updateChats);
  yield takeEvery(chatActions.fetchChatDetail, getChatDetail);
  yield takeEvery(chatActions.sendChat, sendChat);
  yield takeLatest(chatActions.sendChat, sendChatNotification);
  yield takeEvery(chatActions.setChatAsRead, setChatAsRead);
  yield takeEvery(chatActions.deleteChatConversation, deleteChatConversation);
}