// src/actions/messageActions.js
import {
  threadGetList,
  threadGoToMessageId,
  threadLeave, threadMessageGetList,
} from "./threadActions";
import ChatSDK from "../utils/chatSDK";
import {stateGeneratorState} from "../utils/storeHelper";
import {getThreadHistory} from "../utils/listing";
import {
  CHAT_GET_INSTANCE,
  CHAT_SMALL_VERSION,
  CHAT_STATE,
  CHAT_MODAL_PROMPT_SHOWING,
  CHAT_ROUTER_LESS,
  CHAT_SEARCH_RESULT,
  CHAT_SEARCH_SHOW,
  THREAD_NEW,
  THREAD_CHANGED,
  THREAD_FILE_UPLOADING,
  THREAD_REMOVED_FROM,
  THREAD_PARTICIPANTS_LIST_CHANGE,
  THREADS_LIST_CHANGE,
  THREAD_LEAVE_PARTICIPANT,
  THREAD_GET_LIST,
  CHAT_STOP_TYPING,
  CHAT_IS_TYPING,
  CHAT_NOTIFICATION,
  CHAT_NOTIFICATION_CLICK_HOOK,
  CHAT_RETRY_HOOK,
  CHAT_SIGN_OUT_HOOK,
  THREAD_MESSAGE_PIN,
  MESSAGE_PINNED,
  THREAD_GET_MESSAGE_LIST,
  THREAD_CREATE,
  THREAD_GET_MESSAGE_LIST_PARTIAL,
  CHAT_DESTROY,
  CHAT_AUDIO_PLAYER,
  CHAT_AUDIO_RECORDER,
  CHAT_SUPPORT_MODE,
  CHAT_SUPPORT_MODULE_BADGE_SHOWING,
  CHAT_CALL_BOX_SHOWING,
  CHAT_CALL_STATUS,
  CHAT_SELECT_PARTICIPANT_FOR_CALL_SHOWING,
  CHAT_CALL_PARTICIPANT_LIST_PRELOAD,
  CHAT_CALL_PARTICIPANT_LIST,
  CHAT_CALL_PARTICIPANT_LEFT,
  CHAT_CALL_PARTICIPANT_JOINED,
  CHAT_CALL_PARTICIPANT_LIST_CHANGE,
  CHAT_CALL_GROUP_VIDEO_VIEW_MODE,
  CHAT_CALL_GROUP_SETTINGS_SHOWING,
  CHAT_TYPING_HOOK,
  THREAD_UPDATE,
  MESSAGE_UNPIN,
  MESSAGE_PIN,
  THREAD_LAST_ACTIVITY_TIME,
  THREAD_UNREAD_COUNT_UPDATED,
  CHAT_DATEPICKER,
  CHAT_MODAL_CALL_ERROR_SHOWING, THREAD_GET_LIST_PARTIAL
} from "../constants/actionTypes";
import {messageInfo} from "./messageActions";
import {THREAD_HISTORY_LIMIT_PER_REQUEST} from "../constants/historyFetchLimits";
import {
  BUSY_DROP_TIME_OUT,
  CALL_DIV_ID,
  CHAT_CALL_BOX_NORMAL,
  CHAT_CALL_STATUS_INCOMING,
  CHAT_CALL_STATUS_OUTGOING,
  CHAT_CALL_STATUS_STARTED
} from "../constants/callModes";
import {
  findInTyping,
  dispatchThreadChange,
  resetChatCall,
  callParticipantStandardization,
  isGroup,
  isScreenShare,
  isScreenShareOwnerIsMe
} from "../utils/helpers";
import {CHAT_SETTINGS} from "../constants/cookieKeys";


let firstReadyPassed = false;

const {CANCELED, SUCCESS} = stateGeneratorState;


export const chatSetInstance = config => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_GET_INSTANCE(),
      payload: null
    });
    new ChatSDK({
      config,
      onThreadEvents: (data, type) => {
        const {result} = data || {};
        const {thread} = result || {};
        switch (type) {
          case THREAD_NEW: {
            if (getState().thread.thread.id === thread.id) {
              return;
            }
            if (data.redirectToThread) {
              dispatch(threadMessageGetList(null, null, true));
            }
            return dispatch({
              type: type,
              payload: {redirectToThread: data.redirectToThread, thread}
            });
          }
          case THREAD_LEAVE_PARTICIPANT:
            dispatch({
              type: type,
              payload: {threadId: data.threadId, id: result.participant.id}
            });
            return dispatchThreadChange(getState(), thread, dispatch);
          case THREADS_LIST_CHANGE:
            return dispatch({
              type: type,
              payload: result.threads
            })
          case THREAD_PARTICIPANTS_LIST_CHANGE:
            return dispatch({
              type: type,
              payload: {...result, threadId: data.threadId}
            });
          case MESSAGE_UNPIN:
          case MESSAGE_PIN: {
            const {thread: id, pinMessage} = result;
            const isPin = type === MESSAGE_PIN;
            if (isPin) {
              if (pinMessage.notifyAll) {
                dispatch(messageInfo(id, pinMessage.messageId)).then(message => {
                  return dispatch({
                    type: MESSAGE_PINNED,
                    payload: message
                  });
                });
              }
            }
            return dispatch({
              type: THREAD_MESSAGE_PIN,
              payload: {id, pinMessageVO: isPin ? pinMessage : null}
            });
          }
          case THREAD_REMOVED_FROM:
            return dispatch(threadLeave(thread, true));
          case THREAD_LAST_ACTIVITY_TIME:
            return;
          default:
            data.changeType = type;
            if (result) {
              if (!thread) {
                return;
              }
              if (!thread.id) {
                return;
              }
            }
            return dispatchThreadChange(getState(), result ? thread : data, dispatch);
        }
      },
      onMessageEvents: (message, type) => {
        const {thread} = getState().thread;

        if (window.document.hasFocus() && type === "MESSAGE_NEW") {
          if (thread) {
            if (thread.id !== message.threadId) {
              return;
            }
          }
        }
        (!message.uniqueId && message.id) && (message.uniqueId = message.id);
        dispatch({
          type: type,
          payload: message
        });
      },
      onCallEvents: (data, type) => {
        const state = getState();
        const oldCall = state.chatCallStatus;
        const user = state.user.user;
        switch (type) {
          case "CALL_SESSION_CREATED":
            data.isOwner = true;
            return dispatch(chatCallStatus(oldCall.status, data));
          case "CALL_PARTICIPANT_LEFT": {
            if (data && data[0] && data[0]?.userId === user?.id) {
              resetChatCall(dispatch, oldCall.call, oldCall?.call?.callId, getState());
              return dispatch(chatCallBoxShowing(false, null, null));
            }
            return dispatch(chatCallParticipantLeft(callParticipantStandardization(data)));
          }
          case "CALL_PARTICIPANT_JOINED":
            return dispatch(chatCallParticipantJoined(callParticipantStandardization(data)));
          case "CALL_PARTICIPANT_MUTE":
          case "CALL_PARTICIPANT_UNMUTE": {
            const trueCallObject = callParticipantStandardization(data.map(e => ({
              mute: e.mute,
              id: e.participantVO.id
            })));
            return dispatch(chatCallParticipantListChange(trueCallObject));
          }
          case "REJECT_GROUP_CALL":
            return dispatch(chatCallParticipantListChange(callParticipantStandardization([data])));
          case "TURN_OFF_VIDEO_CALL":
          case "TURN_ON_VIDEO_CALL":
            return dispatch(chatCallParticipantListChange(callParticipantStandardization(data, {
              video: type === "TURN_ON_VIDEO_CALL",
              videoMute: type === "TURN_OFF_VIDEO_CALL"
            })));
          case "RECEIVE_CALL":
            if (oldCall && (oldCall?.call?.id || oldCall?.call?.callId || oldCall.status === CHAT_CALL_STATUS_OUTGOING)) {
              const chatSDK = state.chatInstance.chatSDK;
              return setTimeout(() => chatSDK.rejectCall(data.callId), BUSY_DROP_TIME_OUT);
            }
            dispatch(chatCallBoxShowing(CHAT_CALL_BOX_NORMAL, data.conversationVO || {}, data.creatorVO));
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_INCOMING, data));
          case "CALL_STARTED": {
            const callId = data?.callId;
            data.isOwner = user.id === oldCall.call.creatorId;
            if (data.isOwner) {
              dispatch(chatCallGetParticipantList(callId, null, true)).then(participants => {
                const oldThreadParticipant = getState().chatCallParticipantList.participants;
                const newMap = oldThreadParticipant.map(participant => {
                  const found = participants.find(finded => {
                    if (participant.id === finded.id) {
                      return finded;
                    }
                  });
                  if (found) {
                    return found;
                  }
                  return participant;
                });
                dispatch(chatCallGetParticipantList(callId, newMap));
              });
            } else {
              dispatch(chatCallGetParticipantList(callId));
            }
            if (+data?.chatDataDto?.screenShareUser) {
              data.screenShare = {
                screenOwner: {id: +data?.chatDataDto?.screenShareUser},
                screenshare: data?.chatDataDto.screenShare,
                topicSend: data?.chatDataDto.screenShare
              }
            }
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {callId, ...oldCall.call, ...data}))
          }
          case "CALL_ENDED":
            resetChatCall(dispatch, oldCall.call, data?.callId, getState());
            return;
          case "CALL_DIVS":
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {...oldCall.call, ...data}));
          case "START_SCREEN_SHARE":
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {...oldCall.call, screenShare: {...data}}));
          case "END_SCREEN_SHARE":
            delete oldCall.call.screenShare;
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {...oldCall.call}));
          case "START_RECORDING_CALL":
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {...oldCall.call, recording: {...data}}));
          case "STOP_RECORDING_CALL":
            delete oldCall.call.recording;
            return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {...oldCall.call}));
          case "SWITCH_TO_GROUP_CALL": {
            const oldThread = state.threads.threads.find(e => e.id === data.threadId);
            if (oldThread) {
              if (oldCall?.call?.callId === data?.callId) {
                if (oldCall?.status === CHAT_CALL_STATUS_INCOMING) {
                  return;
                }
              }
              dispatch(chatCallBoxShowing(CHAT_CALL_BOX_NORMAL, oldThread));
              return dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, {
                ...oldCall.call,
                conversationVO: oldThread,
                group: true
              }));
            }
            break;
          }
          default:
            break;
        }
      },
      onCallStreamEvents: (data, type) => {
        switch (type) {
          case "USER_SPEAKING": {
            if (!getState()?.chatCallStatus?.call) {
              return;
            }
            const correctData = {audioLevel: data.audioLevel, id: data.userId, audioLevelReceivedTime: Date.now()};
            const oldParticipants = getState().chatCallParticipantList.participants;
            if (oldParticipants && oldParticipants.find(e => e.id === correctData.id)?.audioLevel === correctData.audioLevel) {
              return;
            }
            return dispatch(chatCallParticipantListChange(correctData));
          }
          default:
            break;
        }
      },
      onContactsEvents: (contacts, type) => {
        dispatch({
          type: type,
          payload: contacts
        });
      },
      onFileUploadEvents: message => {
        dispatch({
          type: THREAD_FILE_UPLOADING,
          payload: {...message, hasError: message.state === "UPLOAD_ERROR"}
        });
      },
      onSystemEvents: ({result, type}) => {
        if (type === "IS_TYPING") {
          const {thread: threadId, user} = result;
          const {threadId: oldThreadId, userId: oldUserId} = findInTyping(threadId, user.userId);

          if (oldThreadId) {
            const timeOutName = `${oldThreadId}${oldUserId}TimeOut`;
            clearTimeout(window[timeOutName]);
          } else {
            findInTyping(threadId, user.userId, false, true);
          }
          const timeOutName = `${threadId}${user.userId}TimeOut`;
          window[timeOutName] = setTimeout(() => {
            findInTyping(threadId, user.userId, true);
            dispatch({
              type: CHAT_STOP_TYPING,
              payload: {threadId, user}
            });
          }, 1500);
          const lastThread = getState().threads.threads.find(e => e.id === threadId);
          if (lastThread && lastThread.isTyping && lastThread.isTyping.isTyping) {
            return;
          }
          return dispatch({
            type: CHAT_IS_TYPING,
            payload: {threadId, user}
          });
        }
        if (type === "SERVER_TIME") {
          window._universalTalkTimerDiff = Date.now() - result.time;
        }
      },
      onChatState(e) {
        dispatch({
          type: CHAT_STATE,
          payload: e
        });
      },
      onChatError(e) {

        if (e && e.code) {
          if (e.code === 208) {
            const event = new CustomEvent('podchat-error', {detail: e});
            document.body.dispatchEvent(event);
          }
          if (e.code === 21) {
            const {chatRetryHook, chatInstance} = getState();
            if (chatRetryHook) {
              chatRetryHook().then(token => {
                chatInstance.chatSDK.setToken(token);
                chatInstance.chatSDK.reconnect();
              });
            }
          }

        }
      },
      onChatReady(e) {
        if (firstReadyPassed) {
          dispatch(restoreChatState());
        }
        firstReadyPassed = true;

        dispatch({
          type: CHAT_GET_INSTANCE("SUCCESS"),
          payload: e
        })
      }
    });
  }
};

export const chatGetImage = (hashCode, size, quality, crop) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    return chatSDK.getImageFromPodspace(hashCode, size, quality, crop);
  }
};

export const chatGetFile = (hashCode, callBack, params) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    return chatSDK.getFileFromPodspace(hashCode, callBack, params);
  }
};

export const chatCancelFileDownload = (uniqueId) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    return chatSDK.cancelFileDownload(uniqueId)
  }
};

export const chatUploadImage = (image, threadId, callBack) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.uploadImage(image, threadId).then(callBack);
  }
};

export const chatDestroy = () => {
  return (dispatch) => {
    firstReadyPassed = false;
    dispatch({
      type: CHAT_DESTROY,
      payload: null
    });
  }
};

export const restoreChatState = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;

    const currentCall = state.chatCallStatus;

    if (currentCall) {
      const {call} = currentCall;
      if (currentCall.status === CHAT_CALL_STATUS_STARTED) {
        if (call.group || (call.conversationVO && isGroup(call.conversationVO))) {
          dispatch(chatCallGetParticipantList(call.id || call.callId));
        }
      }
    }

    const threads = state.threads.threads;
    dispatch({
      type: THREAD_GET_LIST_PARTIAL(CANCELED)
    });
    dispatch(threadGetList(0, threads.length, null, true)).then(payload => {
      const {threads} = payload;
      dispatch({
        type: THREADS_LIST_CHANGE,
        payload: threads
      });
    });

    const pastThread = state.thread.thread;
    if (pastThread.id && !pastThread.onTheFly) {
      chatSDK.getThreadInfo({threadIds: [pastThread.id]}).then(thread => {
        const {messages, threadId, hasNext, hasPrevious, fetching, fetched} = state.threadMessages;
        dispatch({
          type: THREAD_CREATE("CACHE"),
          payload: thread
        });
        const needToFetchSomethingCondition = (!pastThread.lastMessageVO && thread.lastMessageVO) || (pastThread.lastMessageVO.id !== thread.lastMessageVO.id);
        if (!needToFetchSomethingCondition) {
          return;
        }
        const lastMassage = messages[messages.length - 1];
        const firstInitial = !thread.lastMessageVO || (lastMassage && thread.lastMessageVO.time < lastMassage.time);
        const offsetOrTimeNanos = firstInitial ? undefined : lastMassage.time + 200;
        getThreadHistory(chatSDK, threadId, THREAD_HISTORY_LIMIT_PER_REQUEST, offsetOrTimeNanos, !firstInitial).then(payload => {
          const {messages} = payload;
          if (firstInitial) {
            dispatch({
              type: THREAD_GET_MESSAGE_LIST(SUCCESS),
              payload
            });
            threadGoToMessageId(messages[messages.length - 1]);
          } else {
            if (!hasNext) {
              return dispatch({
                type: THREAD_GET_MESSAGE_LIST_PARTIAL(SUCCESS),
                payload
              });
            }
          }

        })
      });
    }
  }
};

export const chatSmallVersion = isSmall => {
  return dispatch => {
    return dispatch({
      type: CHAT_SMALL_VERSION,
      payload: isSmall
    });
  }
};

export const chatSupportMode = isSupportMode => {
  return dispatch => {
    return dispatch({
      type: CHAT_SUPPORT_MODE,
      payload: isSupportMode
    });
  }
};

export const chatSupportModuleBadgeShowing = showing => {
  return dispatch => {
    return dispatch({
      type: CHAT_SUPPORT_MODULE_BADGE_SHOWING,
      payload: showing
    });
  }
};

export const chatCallBoxShowing = (showing, thread, contact) => {
  return dispatch => {
    return dispatch({
      type: CHAT_CALL_BOX_SHOWING,
      payload: {showing, thread, contact}
    });
  }
};

export const chatCallStatus = (status = null, call = null) => {
  return dispatch => {
    return dispatch({
      type: CHAT_CALL_STATUS,
      payload: {status, call}
    });
  }
};

export const chatCallMuteParticipants = (callId, userIds, justChangeTheList = false) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (!justChangeTheList) {
      chatSDK.muteCallParticipants(callId, userIds);
    }
    dispatch(chatCallParticipantListChange(userIds.map(user => {
      return {id: user, mute: true}
    })));
  }
};

export const chatCallUnMuteParticipants = (callId, userIds, justChangeTheList = false) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (!justChangeTheList) {
      chatSDK.unMuteCallParticipants(callId, userIds);
    }
    dispatch(chatCallParticipantListChange(userIds.map(user => {
      return {id: user, mute: false}
    })));
  }
};

export const chatCallRemoveParticipants = (callId, userIds) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.removeCallParticipants(callId, userIds).then(e => {
      dispatch({
        type: CHAT_CALL_PARTICIPANT_LEFT,
        payload: userIds
      });
    });
  }
};

export const chatCallAddParticipants = (callId, contactIds, participants) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.addCallParticipants(callId, contactIds);
    dispatch({
      type: CHAT_CALL_PARTICIPANT_JOINED,
      payload: participants
    });
  }
};

export const chatCallEnded = (callId) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;

    chatSDK.joinCall(callId).then(call => {
      dispatch(chatCallBoxShowing(CHAT_CALL_BOX_NORMAL, thread));
    })
  }
};

export const chatCallGetParticipantList = (callId, payload, direct) => {
  return (dispatch, getState) => {
    if (!callId && !payload) {
      return dispatch({
        type: CHAT_CALL_PARTICIPANT_LIST(CANCELED)
      });
    }
    if (payload) {
      return dispatch({
        type: CHAT_CALL_PARTICIPANT_LIST_PRELOAD,
        payload
      });
    }
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (direct) {
      return chatSDK.getCallParticipants(callId);
    }
    dispatch({
      type: CHAT_CALL_PARTICIPANT_LIST(),
      payload: chatSDK.getCallParticipants(callId)
    });
  }
};

export const chatCallParticipantJoined = participant => {
  return dispatch => {
    dispatch({
      type: CHAT_CALL_PARTICIPANT_JOINED,
      payload: participant
    });
  }
};

export const chatCallParticipantLeft = (participantId) => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_CALL_PARTICIPANT_LEFT,
      payload: participantId
    });
  }
};

export const chatCallParticipantListChange = participants => {
  return dispatch => {
    dispatch({
      type: CHAT_CALL_PARTICIPANT_LIST_CHANGE,
      payload: participants
    });
  }
};

export const chatAcceptCall = (call, video = false, isJoin, thread) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    const options = {joinCall: isJoin, video, cameraPaused: false};
    dispatch(chatCallStatus(CHAT_CALL_STATUS_STARTED, call));
    if (call?.group || call?.conversationVO?.group) {
      const updateThread = thread => {
        const {call, ...other} = thread;
        dispatch({
          type: THREAD_UPDATE,
          payload: other
        });
      }
      if (isJoin) {
        updateThread(thread);
        dispatch(chatCallBoxShowing(CHAT_CALL_BOX_NORMAL, thread));
        setTimeout(() => dispatch(chatCallGetParticipantList(thread.call.id)), 1000);
      } else {
        const thread = state.threads.threads.find(thread => call.conversationVO.id === thread.id);
        thread && updateThread(thread);
      }
    }
    return chatSDK.acceptCall(call.callId || call.id, options);
  }
};

export const chatRejectCall = (call, status) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    const callBackBuilder = () => {
      const isScreenShareCall = isScreenShare(call);
      const isScreenSharingOwnerIsMeResult = isScreenShareCall && isScreenShareOwnerIsMe(call.screenShare, state.user.user);
      if (isScreenShareCall && isScreenSharingOwnerIsMeResult) {
        dispatch(chatCallEndScreenShare());
      }
      if (call.group || call?.conversationVO?.group) {
        const found = state.threads.threads.find(thread => thread.id === call.conversationVO.id);
        if (found) {
          const correctCall = {...call, id: call.callId, screenShare: undefined};
          dispatch({
            type: THREAD_UPDATE,
            payload: {call: correctCall, ...found}
          });
        }
      }
    }
    if (status === CHAT_CALL_STATUS_STARTED) {
      callBackBuilder();
      chatSDK.endCall(call.callId);
    } else {
      if (call) {
        if (status !== CHAT_CALL_STATUS_OUTGOING) {
          callBackBuilder();
        }
        chatSDK.rejectCall(call.callId);
      }
    }
    resetChatCall(dispatch, call);
    dispatch(chatCallBoxShowing(false, null, null));
  }
};

export const chatStartCall = (threadId, type, params, callBack) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.startCall(threadId, type, params, callBack);
    dispatch(chatCallStatus(CHAT_CALL_STATUS_OUTGOING, {type: type === "video" ? 1 : 0}));
  }
};

export const chatSelectParticipantForCallShowing = data => {
  return dispatch => {
    return dispatch({
      type: CHAT_SELECT_PARTICIPANT_FOR_CALL_SHOWING,
      payload: data
    });
  }
};

export const chatStartGroupCall = (threadId, invitees, type, params, callBack) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.startGroupCall(threadId, invitees, type, params, result => {
      if (!threadId) {
        dispatch(chatCallStatus(CHAT_CALL_STATUS_OUTGOING, {type: type === "video" ? 1 : 0}));
      }
      callBack && callBack(result);
    });

    //If thread created before show callBox and play ringtone
    if (threadId) {
      dispatch(chatCallStatus(CHAT_CALL_STATUS_OUTGOING, {type: type === "video" ? 1 : 0}));
    }
  }
};

export const chatCallStartScreenShare = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (state.chatCallStatus.call) {
      chatSDK.startScreenShare(state.chatCallStatus.call.callId);
    }
  }
};

export const chatCallEndScreenShare = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (state.chatCallStatus.call) {
      chatSDK.endScreenShare(state.chatCallStatus.call.callId);
    }
  }
};

export const chatCallTurnOnVideo = (userId, justChangeTheList) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    const callId = state.chatCallStatus.call?.callId;
    if (callId && !justChangeTheList) {
      chatSDK.turnOnVideoCall(callId);
    }
    dispatch(chatCallParticipantListChange([{id: userId, video: true}]));
  }
};

export const chatCallTurnOffVideo = (userId, justChangeTheList) => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    const callId = state.chatCallStatus.call?.callId;
    if (callId && !justChangeTheList) {
      chatSDK.turnOffVideoCall(callId);
    }
    dispatch(chatCallParticipantListChange([{id: userId, video: false}]));
  }
};

export const chatStartCallRecording = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (state.chatCallStatus.call) {
      chatSDK.startRecordingCall(state.chatCallStatus.call.callId);
    }
  }
};

export const chatStopCallRecording = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    if (state.chatCallStatus.call) {
      chatSDK.stopRecordingCall(state.chatCallStatus.call.callId);
    }
  }
};

export const chatCallGroupVideoViewMode = type => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_CALL_GROUP_VIDEO_VIEW_MODE,
      payload: type
    });
  }
};

export const chatCallGroupSettingsShowing = showing => {
  return dispatch => {
    dispatch({
      type: CHAT_CALL_GROUP_SETTINGS_SHOWING,
      payload: showing
    });
  }
};

export const chatRouterLess = isRouterLess => {
  return dispatch => {
    return dispatch({
      type: CHAT_ROUTER_LESS,
      payload: isRouterLess
    });
  }
};

export const chatNotification = isNotification => {
  return dispatch => {
    return dispatch({
      type: CHAT_NOTIFICATION,
      payload: isNotification
    });
  }
};

export const chatNotificationClickHook = chatNotificationClickHook => {
  return {
    type: CHAT_NOTIFICATION_CLICK_HOOK,
    payload: thread => chatNotificationClickHook.bind(null, thread)
  }
};

export const chatRetryHook = chatRetryHookHook => {
  return {
    type: CHAT_RETRY_HOOK,
    payload: () => chatRetryHookHook
  }
};

export const chatSignOutHook = chatSignOutHookHook => {
  return {
    type: CHAT_SIGN_OUT_HOOK,
    payload: () => chatSignOutHookHook
  }
};
export const chatTypingHook = onTypingHook => {
  return {
    type: CHAT_TYPING_HOOK,
    payload: () => onTypingHook
  }
};

export const chatModalPrompt = (isShowing, message, onApply, onCancel, confirmText, customBody, extraMessage, noConfirmButton, noCancelButton) => {
  return dispatch => {
    return dispatch({
      type: CHAT_MODAL_PROMPT_SHOWING,
      payload: {
        isShowing,
        message,
        extraMessage,
        onApply,
        onCancel,
        confirmText,
        customBody,
        noConfirmButton,
        noCancelButton
      }
    });
  }
};

export const chatModalCallError = (isShowing, error) => {
  return dispatch => {
    return dispatch({
      type: CHAT_MODAL_CALL_ERROR_SHOWING,
      payload: {
        isShowing,
        error
      }
    });
  }
};

export const chatSearchResult = (isShowing, filteredThreads, filteredContacts) => {
  return dispatch => {
    return dispatch({
      type: CHAT_SEARCH_RESULT,
      payload: {
        isShowing,
        filteredThreads,
        filteredContacts
      }
    });
  }
};

export const chatSearchShow = isShow => {
  return dispatch => {
    return dispatch({
      type: CHAT_SEARCH_SHOW,
      payload: isShow
    });
  }
};

export const chatClearCache = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.clearCache();
  }
};

export const chatAudioPlayer = data => {
  return (dispatch, getState) => {
    const state = getState();
    const chatAudioPlayer = state.chatAudioPlayer;
    if (chatAudioPlayer) {
      const {player, message} = chatAudioPlayer;
      if (!data || data.message.id !== message.id) {
        player.stop();
      }
    }
    dispatch({
      type: CHAT_AUDIO_PLAYER,
      payload: data ? data : null
    });
  }
};
export const chatAudioRecorder = recording => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_AUDIO_RECORDER,
      payload: recording
    });
  }
};

export const startTyping = threadId => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.startTyping(threadId);
  }
};

export const stopTyping = () => {
  return (dispatch, getState) => {
    const state = getState();
    const chatSDK = state.chatInstance.chatSDK;
    chatSDK.stopTyping();
  }
};

export const chatSettings = payload => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_SETTINGS,
      payload
    });
  }
};

export const chatDatepicker = payload => {
  return (dispatch, getState) => {
    dispatch({
      type: CHAT_DATEPICKER,
      payload
    });
  }
};
