import React__default, { useEffect, useCallback, useState, useReducer, useRef, useMemo } from 'react';
import { f as format } from './index-e7f4cbdf.js';
import { U as UserProfileProvider } from './UserProfileContext-a59f0533.js';
import { _ as _objectSpread2 } from './_rollupPluginBabelHelpers-a69fd1ce.js';
import { c as compareIds } from './compareIds-aca19765.js';
import { P as PUBSUB_TOPICS } from './topics-247fcf3a.js';
import { ChannelType } from '@sendbird/chat';
import { OpenChannelHandler } from '@sendbird/chat/openChannel';
import { u as uuidv4 } from './uuid-2e8efc75.js';
import useSendbirdStateContext from './useSendbirdStateContext.js';

const getMessageCreatedAt = message => format(message.createdAt, 'p');
const shouldFetchMore = (messageLength, maxMessages) => {
  if (typeof maxMessages !== 'number') {
    return true;
  }
  if (typeof maxMessages === 'number' && maxMessages > messageLength) {
    return true;
  }
  return false;
};

/* eslint-disable default-param-last */
const scrollIntoLast = function () {
  let initialTry = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
  let scrollRef = arguments.length > 1 ? arguments[1] : undefined;
  const MAX_TRIES = 10;
  const currentTry = initialTry;
  if (currentTry > MAX_TRIES) {
    return;
  }
  try {
    const scrollDOM = (scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current) || document.querySelector('.sendbird-openchannel-conversation-scroll__container__item-container');
    // eslint-disable-next-line no-multi-assign
    scrollDOM.scrollTop = scrollDOM.scrollHeight;
  } catch (error) {
    setTimeout(() => {
      scrollIntoLast(currentTry + 1, scrollRef);
    }, 500 * currentTry);
  }
};
const isSameGroup = (message, comparingMessage) => {
  var _sender, _sender2, _message_$sender, _comparingMessage_$se;
  if (!(message && comparingMessage && message !== null && message !== void 0 && message.messageType && message.messageType !== 'admin' && comparingMessage !== null && comparingMessage !== void 0 && comparingMessage.messageType && comparingMessage.messageType !== 'admin' && message !== null && message !== void 0 && message.sender && comparingMessage !== null && comparingMessage !== void 0 && comparingMessage.sender && message !== null && message !== void 0 && message.createdAt && comparingMessage !== null && comparingMessage !== void 0 && comparingMessage.createdAt && message !== null && message !== void 0 && (_sender = message.sender) !== null && _sender !== void 0 && _sender.userId && comparingMessage !== null && comparingMessage !== void 0 && (_sender2 = comparingMessage.sender) !== null && _sender2 !== void 0 && _sender2.userId)) {
    return false;
  }
  // to fix typecasting
  const message_ = message;
  const comparingMessage_ = comparingMessage;
  return (message_ === null || message_ === void 0 ? void 0 : message_.sendingStatus) === (comparingMessage_ === null || comparingMessage_ === void 0 ? void 0 : comparingMessage_.sendingStatus) && (message_ === null || message_ === void 0 ? void 0 : (_message_$sender = message_.sender) === null || _message_$sender === void 0 ? void 0 : _message_$sender.userId) === (comparingMessage_ === null || comparingMessage_ === void 0 ? void 0 : (_comparingMessage_$se = comparingMessage_.sender) === null || _comparingMessage_$se === void 0 ? void 0 : _comparingMessage_$se.userId) && getMessageCreatedAt(message) === getMessageCreatedAt(comparingMessage);
};
const compareMessagesForGrouping = (prevMessage, currMessage, nextMessage) => [isSameGroup(prevMessage, currMessage), isSameGroup(currMessage, nextMessage)];
const kFormatter = num => {
  if (Math.abs(num) > 999999) {
    return `${(Math.abs(num) / 1000000).toFixed(1)}M`;
  }
  if (Math.abs(num) > 999) {
    return `${(Math.abs(num) / 1000).toFixed(1)}K`;
  }
  return `${num}`;
};
const isOperator = (openChannel, userId) => {
  const operators = openChannel === null || openChannel === void 0 ? void 0 : openChannel.operators;
  if (operators.map(operator => operator.userId).indexOf(userId) < 0) {
    return false;
  }
  return true;
};
const isDisabledBecauseFrozen = (openChannel, userId) => {
  const isFrozen = openChannel === null || openChannel === void 0 ? void 0 : openChannel.isFrozen;
  return isFrozen && !isOperator(openChannel, userId);
};
const isDisabledBecauseMuted = (mutedParticipantIds, userId) => {
  return mutedParticipantIds.indexOf(userId) > -1;
};
const fetchWithListQuery = (listQuery, logger, eachQueryNextCallback) => {
  const fetchList = query => {
    const {
      hasNext
    } = query;
    if (hasNext) {
      query.next().then(users => {
        eachQueryNextCallback(users);
        fetchList(query);
      }).catch(error => {
        logger.warning('OpenChannel | FetchUserList failed', error);
      });
    } else {
      logger.info('OpenChannel | FetchUserList finished');
    }
  };
  logger.info('OpenChannel | FetchUserList start', listQuery);
  fetchList(listQuery);
};
const pxToNumber = px => {
  if (typeof px === 'number') {
    return px;
  }
  if (typeof px === 'string') {
    const parsed = Number.parseFloat(px);
    if (!Number.isNaN(parsed)) {
      return parsed;
    }
  }
  return null;
};

const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL';
const SET_CHANNEL_INVALID = 'SET_CHANNEL_INVALID';
const RESET_MESSAGES = 'RESET_MESSAGES';
const EXIT_CURRENT_CHANNEL = 'EXIT_CURRENT_CHANNEL';
const GET_PREV_MESSAGES_START = 'GET_PREV_MESSAGES_START';
const GET_PREV_MESSAGES_SUCESS = 'GET_PREV_MESSAGES_SUCESS';
const GET_PREV_MESSAGES_FAIL = 'GET_PREV_MESSAGES_FAIL';
const SENDING_MESSAGE_FAILED = 'SENDING_MESSAGE_FAILED';
const SENDING_MESSAGE_SUCCEEDED = 'SENDING_MESSAGE_SUCCEEDED';
const SENDING_MESSAGE_START = 'SENDING_MESSAGE_START';
const RESENDING_MESSAGE_START = 'RESENDING_MESSAGE_START';
const FETCH_PARTICIPANT_LIST = 'FETCH_PARTICIPANT_LIST';
const FETCH_BANNED_USER_LIST = 'FETCH_BANNED_USER_LIST';
const FETCH_MUTED_USER_LIST = 'FETCH_MUTED_USER_LIST';
const TRIM_MESSAGE_LIST = 'TRIM_MESSAGE_LIST';

// event handlers
const ON_MESSAGE_RECEIVED = 'ON_MESSAGE_RECEIVED';
const ON_MESSAGE_UPDATED = 'ON_MESSAGE_UPDATED';
const ON_MESSAGE_DELETED = 'ON_MESSAGE_DELETED';
const ON_MESSAGE_DELETED_BY_REQ_ID = 'ON_MESSAGE_DELETED_BY_REQ_ID';
const ON_OPERATOR_UPDATED = 'ON_OPERATOR_UPDATED';
const ON_USER_ENTERED = 'ON_USER_ENTERED';
const ON_USER_EXITED = 'ON_USER_EXITED';
const ON_USER_MUTED = 'ON_USER_MUTED';
const ON_USER_UNMUTED = 'ON_USER_UNMUTED';
const ON_USER_BANNED = 'ON_USER_BANNED';
const ON_USER_UNBANNED = 'ON_USER_UNBANNED';
const ON_CHANNEL_FROZEN = 'ON_CHANNEL_FROZEN';
const ON_CHANNEL_UNFROZEN = 'ON_CHANNEL_UNFROZEN';
const ON_CHANNEL_CHANGED = 'ON_CHANNEL_CHANGED';
const ON_CHANNEL_DELETED = 'ON_CHANNEL_DELETED';
const ON_META_DATA_CREATED = 'ON_META_DATA_CREATED';
const ON_META_DATA_UPDATED = 'ON_META_DATA_UPDATED';
const ON_META_DATA_DELETED = 'ON_META_DATA_DELETED';
const ON_META_COUNTERS_CREATED = 'ON_META_COUNTERS_CREATED';
const ON_META_COUNTERS_UPDATED = 'ON_META_COUNTERS_UPDATED';
const ON_META_COUNTERS_DELETED = 'ON_META_COUNTERS_DELETED';
const ON_MENTION_RECEIVED = 'ON_MENTION_RECEIVED';

/* eslint-disable  @typescript-eslint/no-explicit-any */ // @ts-ignore: Unreachable code error
function reducer(state, action) {
  switch (action.type) {
    case RESET_MESSAGES:
      {
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: []
        });
      }
    case EXIT_CURRENT_CHANNEL:
      {
        var _action$payload, _state$currentOpenCha;
        if (((_action$payload = action.payload) === null || _action$payload === void 0 ? void 0 : _action$payload.url) === ((_state$currentOpenCha = state.currentOpenChannel) === null || _state$currentOpenCha === void 0 ? void 0 : _state$currentOpenCha.url)) {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            currentOpenChannel: null
          });
        }
        return state;
      }
    case SET_CURRENT_CHANNEL:
      {
        const gottenChannel = action.payload;
        const operators = gottenChannel.operators;
        if (!state.isInvalid && state.currentOpenChannel && state.currentOpenChannel.url && state.currentOpenChannel.url === gottenChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          currentOpenChannel: gottenChannel,
          isInvalid: false,
          operators: operators,
          participants: operators,
          bannedParticipantIds: [],
          mutedParticipantIds: []
        });
      }
    case SET_CHANNEL_INVALID:
      {
        return _objectSpread2(_objectSpread2({}, state), {}, {
          isInvalid: true
        });
      }
    case GET_PREV_MESSAGES_START:
      {
        return _objectSpread2(_objectSpread2({}, state), {}, {
          loading: true
        });
      }
    case GET_PREV_MESSAGES_SUCESS:
    case GET_PREV_MESSAGES_FAIL:
      {
        const isFailed = action.type === GET_PREV_MESSAGES_FAIL;
        const {
          currentOpenChannel = {},
          messages = [],
          hasMore,
          lastMessageTimestamp
        } = action.payload;
        const actionChannelUrl = currentOpenChannel.url;
        const receivedMessages = isFailed ? [] : messages;
        const _hasMore = isFailed ? false : hasMore;
        const _lastMessageTimestamp = isFailed ? 0 : lastMessageTimestamp;
        const stateChannel = state.currentOpenChannel;
        const stateChannelUrl = stateChannel.url;
        if (actionChannelUrl !== stateChannelUrl) {
          return state;
        }
        const filteredAllMessages = state.allMessages.filter(message => !receivedMessages.find(_ref => {
          let {
            messageId
          } = _ref;
          return compareIds(messageId, message.messageId);
        }));
        return _objectSpread2(_objectSpread2({}, state), {}, {
          loading: false,
          initialized: true,
          hasMore: _hasMore,
          lastMessageTimestamp: _lastMessageTimestamp,
          allMessages: [...receivedMessages, ...filteredAllMessages]
        });
      }
    case SENDING_MESSAGE_START:
      {
        const {
          message,
          channel
        } = action.payload;
        if ((channel === null || channel === void 0 ? void 0 : channel.url) !== state.currentOpenChannel.url || state.allMessages.some(m => m.reqId === message.reqId)
        // Handing failed first than sending start issue
        ) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: [...state.allMessages, message]
        });
      }
    case SENDING_MESSAGE_SUCCEEDED:
      {
        const sentMessage = action.payload;
        const newMessages = state.allMessages.map(m => compareIds(m.reqId, sentMessage.reqId) ? sentMessage : m);
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: newMessages
        });
      }
    case SENDING_MESSAGE_FAILED:
      {
        const sentMessage = action.payload;
        sentMessage.sendingStatus = 'failed';
        if (!state.allMessages.some(m => (m === null || m === void 0 ? void 0 : m.reqId) === (sentMessage === null || sentMessage === void 0 ? void 0 : sentMessage.reqId))) {
          // Handling failed first than sending start issue
          return _objectSpread2(_objectSpread2({}, state), {}, {
            allMessages: [...state.allMessages.filter(m => !compareIds(m.reqId, sentMessage)), sentMessage]
          });
        } else {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            allMessages: state.allMessages.map(m => compareIds(m.reqId, sentMessage.reqId) ? sentMessage : m)
          });
        }
      }
    case TRIM_MESSAGE_LIST:
      {
        var _action$payload2;
        const {
          allMessages
        } = state;
        const messageLimit = (_action$payload2 = action.payload) === null || _action$payload2 === void 0 ? void 0 : _action$payload2.messageLimit;
        if (messageLimit && messageLimit > 0 && (allMessages === null || allMessages === void 0 ? void 0 : allMessages.length) > messageLimit) {
          const sliceAt = allMessages.length - messageLimit;
          return _objectSpread2(_objectSpread2({}, state), {}, {
            allMessages: allMessages.slice(sliceAt)
          });
        }
        return state;
      }
    case RESENDING_MESSAGE_START:
      {
        const eventedChannel = action.payload.channel;
        const resentMessage = action.payload.message;
        if (eventedChannel.url !== state.currentOpenChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: state.allMessages.map(m => compareIds(m.reqId, resentMessage.reqId) ? resentMessage : m)
        });
      }
    case FETCH_PARTICIPANT_LIST:
      {
        const eventedChannel = action.payload.channel;
        const fetchedParticipantList = action.payload.users;
        if (eventedChannel.url !== state.currentOpenChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          participants: [...state.participants, ...fetchedParticipantList]
          // Should check duplication
        });
      }

    case FETCH_BANNED_USER_LIST:
      {
        const eventedChannel = action.payload.channel;
        const fetchedBannedUserList = action.payload.users;
        if (eventedChannel.url !== state.currentOpenChannel.url || !fetchedBannedUserList.every(user => typeof user.userId === 'string')) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          bannedParticipantIds: [...state.bannedParticipantIds, ...fetchedBannedUserList.map(user => user.userId)]
          // Should check duplication
        });
      }

    case FETCH_MUTED_USER_LIST:
      {
        const eventedChannel = action.payload.channel;
        const fetchedMutedUserList = action.payload.users;
        if (eventedChannel.url !== state.currentOpenChannel.url || !fetchedMutedUserList.every(user => typeof user.userId === 'string')) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          mutedParticipantIds: [...state.mutedParticipantIds, ...fetchedMutedUserList.map(user => user.userId)]
          // Should check duplication
        });
      }
    // events
    case ON_MESSAGE_RECEIVED:
      {
        const eventedChannel = action.payload.channel;
        const receivedMessage = action.payload.message;
        const {
          currentOpenChannel
        } = state;
        if (!compareIds(eventedChannel.url, currentOpenChannel.url) || !(state.allMessages.map(message => message.messageId).indexOf(receivedMessage.messageId) < 0)) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: [...state.allMessages, receivedMessage]
        });
      }
    case ON_MESSAGE_UPDATED:
      {
        const eventedChannel = action.payload.channel;
        const updatedMessage = action.payload.message;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: state.allMessages.map(message => message.isIdentical(updatedMessage) ? updatedMessage : message)
        });
      }
    case ON_MESSAGE_DELETED:
      {
        const eventedChannel = action.payload.channel;
        const deletedMessageId = action.payload.messageId;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: state.allMessages.filter(message => !compareIds(message.messageId, deletedMessageId))
        });
      }
    case ON_MESSAGE_DELETED_BY_REQ_ID:
      {
        return _objectSpread2(_objectSpread2({}, state), {}, {
          allMessages: state.allMessages.filter(m => !compareIds(m.reqId, action.payload))
        });
      }
    case ON_OPERATOR_UPDATED:
      {
        const eventedChannel = action.payload.channel;
        const updatedOperators = action.payload.operators;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          currentOpenChannel: eventedChannel,
          operators: updatedOperators
        });
      }
    case ON_USER_ENTERED:
      {
        const eventedChannel = action.payload.channel;
        const enteredUser = action.payload.user;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          participants: [...state.participants, enteredUser]
        });
      }
    case ON_USER_EXITED:
      {
        const eventedChannel = action.payload.channel;
        const exitedUser = action.payload.user;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          participants: state.participants.filter(participant => !compareIds(participant.userId, exitedUser.userId))
        });
      }
    case ON_USER_MUTED:
      {
        const eventedChannel = action.payload.channel;
        const mutedUser = action.payload.user;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url || state.mutedParticipantIds.indexOf(mutedUser.userId) >= 0) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          mutedParticipantIds: [...state.mutedParticipantIds, mutedUser.userId]
        });
      }
    case ON_USER_UNMUTED:
      {
        const eventedChannel = action.payload.channel;
        const unmutedUser = action.payload.user;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== eventedChannel.url || state.mutedParticipantIds.indexOf(unmutedUser.userId) < 0) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          mutedParticipantIds: state.mutedParticipantIds.filter(userId => userId !== unmutedUser.userId)
        });
      }
    case ON_USER_BANNED:
      {
        const eventedChannel = action.payload.channel;
        const bannedUser = action.payload.user;
        const currentUser = action.payload.currentUser;
        const currentChannel = state.currentOpenChannel;
        if ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url) === (eventedChannel === null || eventedChannel === void 0 ? void 0 : eventedChannel.url) && (bannedUser === null || bannedUser === void 0 ? void 0 : bannedUser.userId) === (currentUser === null || currentUser === void 0 ? void 0 : currentUser.userId)) {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            currentOpenChannel: null
          });
        } else if ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url) === (eventedChannel === null || eventedChannel === void 0 ? void 0 : eventedChannel.url)) {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            bannedParticipantIds: [...state.bannedParticipantIds, bannedUser.userId]
          });
        }
        return state;
      }
    case ON_USER_UNBANNED:
      {
        const eventedChannel = action.payload.channel;
        const unbannedUser = action.payload.user;
        const currentChannel = state.currentOpenChannel;
        if ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url) === (eventedChannel === null || eventedChannel === void 0 ? void 0 : eventedChannel.url)) {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            bannedParticipantIds: state.bannedParticipantIds.filter(userId => userId !== unbannedUser.userId)
          });
        }
        return state;
      }
    case ON_CHANNEL_FROZEN:
      {
        const frozenChannel = action.payload;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== frozenChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          frozen: true
        });
      }
    case ON_CHANNEL_UNFROZEN:
      {
        const unfrozenChannel = action.payload;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== unfrozenChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          frozen: false
        });
      }
    case ON_CHANNEL_CHANGED:
      {
        const changedChannel = action.payload;
        const currentChannel = state.currentOpenChannel;
        if (!currentChannel || currentChannel.url && currentChannel.url !== changedChannel.url) {
          return state;
        }
        return _objectSpread2(_objectSpread2({}, state), {}, {
          currentOpenChannel: changedChannel
        });
      }
    case ON_CHANNEL_DELETED:
      {
        const deletedChannelUrl = action.payload;
        const currentChannel = state === null || state === void 0 ? void 0 : state.currentOpenChannel;
        if ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url) === deletedChannelUrl) {
          return _objectSpread2(_objectSpread2({}, state), {}, {
            currentOpenChannel: null
          });
        }
        return state;
      }
    case ON_META_DATA_CREATED:
      {
        // const eventedChannel = action.payload.channel;
        // const createdMetaData = action.payload.metaData;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_META_DATA_UPDATED:
      {
        // const eventedChannel = action.payload.channel;
        // const updatedMetaData = action.payload.metaData;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_META_DATA_DELETED:
      {
        // const eventedChannel = action.payload.channel;
        // const deletedMetaDataKeys = action.payload.metaDataKeys;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_META_COUNTERS_CREATED:
      {
        // const eventedChannel = action.payload.channel;
        // const createdMetaCounter = action.payload.metaCounter;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_META_COUNTERS_UPDATED:
      {
        // const eventedChannel = action.payload.channel;
        // const updatedMetaCounter = action.payload.metaCounter;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_META_COUNTERS_DELETED:
      {
        // const eventedChannel = action.payload.channel;
        // const deletedMetaCounterKeys = action.payload.metaCounterKeys;
        // return {
        //   ...state
        // };
        return state;
      }
    case ON_MENTION_RECEIVED:
      {
        // const eventedChannel = action.payload.channel;
        // const mentionedMessage = action.payload.message;
        // return {
        //   ...state
        // };
        return state;
      }
    default:
      return state;
  }
}

const initialState = {
  allMessages: [],
  loading: false,
  initialized: false,
  currentOpenChannel: null,
  isInvalid: false,
  hasMore: false,
  lastMessageTimestamp: 0,
  frozen: false,
  operators: [],
  participants: [],
  bannedParticipantIds: [],
  mutedParticipantIds: []
};

function useSetChannel(_ref, _ref2) {
  let {
    channelUrl,
    sdkInit,
    fetchingParticipants,
    userId,
    currentOpenChannel
  } = _ref;
  let {
    sdk,
    logger,
    messagesDispatcher
  } = _ref2;
  useEffect(() => {
    if (channelUrl && sdkInit && sdk !== null && sdk !== void 0 && sdk.openChannel) {
      if (currentOpenChannel && currentOpenChannel !== null && currentOpenChannel !== void 0 && currentOpenChannel.exit) {
        var _currentOpenChannel$e;
        (_currentOpenChannel$e = currentOpenChannel.exit) === null || _currentOpenChannel$e === void 0 ? void 0 : _currentOpenChannel$e.call(currentOpenChannel).then(() => {
          logger.info('OpenChannel | useSetChannel: Exit from the previous open channel', currentOpenChannel === null || currentOpenChannel === void 0 ? void 0 : currentOpenChannel.url);
          messagesDispatcher({
            type: EXIT_CURRENT_CHANNEL,
            payload: currentOpenChannel
          });
        });
      }
      logger.info('OpenChannel | useSetChannel: Fetching channel', channelUrl);
      sdk.openChannel.getChannel(channelUrl).then(openChannel => {
        logger.info('OpenChannel | useSetChannel: Succeeded to fetch channel', openChannel);
        messagesDispatcher({
          type: SET_CURRENT_CHANNEL,
          payload: openChannel
        });
        openChannel.enter().then(() => {
          if (openChannel.isOperator(userId)) {
            // only operator has a permission to fetch these list
            const bannedParticipantListQuery = openChannel.createBannedUserListQuery();
            const mutedParticipantListQuery = openChannel.createMutedUserListQuery();
            fetchWithListQuery(bannedParticipantListQuery, logger, users => {
              messagesDispatcher({
                type: FETCH_BANNED_USER_LIST,
                payload: {
                  channel: openChannel,
                  users
                }
              });
            });
            fetchWithListQuery(mutedParticipantListQuery, logger, users => {
              messagesDispatcher({
                type: FETCH_MUTED_USER_LIST,
                payload: {
                  channel: openChannel,
                  users
                }
              });
            });
          } else {
            openChannel.getMyMutedInfo().then(mutedInfo => {
              if (mutedInfo !== null && mutedInfo !== void 0 && mutedInfo.isMuted) {
                messagesDispatcher({
                  type: FETCH_MUTED_USER_LIST,
                  payload: {
                    channel: openChannel,
                    users: [sdk === null || sdk === void 0 ? void 0 : sdk.currentUser]
                  }
                });
              }
            });
          }
          if (fetchingParticipants) {
            // fetch participants list
            const participantListQuery = openChannel.createParticipantListQuery({
              limit: openChannel.participantCount
            });
            fetchWithListQuery(participantListQuery, logger, users => {
              messagesDispatcher({
                type: FETCH_PARTICIPANT_LIST,
                payload: {
                  channel: openChannel,
                  users
                }
              });
            });
          }
        }).catch(error => {
          logger.warning('OpenChannel | useSetChannel: Failed to enter channel', {
            channelUrl,
            error
          });
          messagesDispatcher({
            type: SET_CHANNEL_INVALID,
            payload: null
          });
        });
      }).catch(error => {
        logger.warning('OpenChannel | useSetChannel: Failed to fetch channel', {
          channelUrl,
          error
        });
        messagesDispatcher({
          type: SET_CHANNEL_INVALID,
          payload: null
        });
      });
    }
  }, [channelUrl, sdkInit, fetchingParticipants]);
}

function useHandleChannelEvents(_ref, _ref2) {
  let {
    currentOpenChannel,
    checkScrollBottom
  } = _ref;
  let {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef
  } = _ref2;
  useEffect(() => {
    var _sdk$openChannel;
    const messageReceiverId = uuidv4();
    if (currentOpenChannel && currentOpenChannel.url && sdk !== null && sdk !== void 0 && (_sdk$openChannel = sdk.openChannel) !== null && _sdk$openChannel !== void 0 && _sdk$openChannel.addOpenChannelHandler) {
      var _sdk$openChannel2;
      logger.info('OpenChannel | useHandleChannelEvents: Setup evnet handler', messageReceiverId);
      const channelHandlerParams = {
        onMessageReceived: (channel, message) => {
          const scrollToEnd = checkScrollBottom();
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMessageReceived', {
            channelUrl,
            message
          });
          messagesDispatcher({
            type: ON_MESSAGE_RECEIVED,
            payload: {
              channel,
              message
            }
          });
          if (scrollToEnd) {
            try {
              setTimeout(() => {
                scrollIntoLast(0, scrollRef);
              });
            } catch (error) {
              logger.warning('OpenChannel | onMessageReceived | scroll to end failed');
            }
          }
        },
        onMessageUpdated: (channel, message) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMessageUpdated', {
            channelUrl,
            message
          });
          messagesDispatcher({
            type: ON_MESSAGE_UPDATED,
            payload: {
              channel,
              message
            }
          });
        },
        onMessageDeleted: (channel, messageId) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMessageDeleted', {
            channelUrl,
            messageId
          });
          messagesDispatcher({
            type: ON_MESSAGE_DELETED,
            payload: {
              channel,
              messageId
            }
          });
        },
        onOperatorUpdated: (channel, operators) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onOperatorUpdated', {
            channelUrl,
            operators
          });
          messagesDispatcher({
            type: ON_OPERATOR_UPDATED,
            payload: {
              channel,
              operators
            }
          });
        },
        onUserEntered: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserEntered', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_ENTERED,
            payload: {
              channel,
              user
            }
          });
        },
        onUserExited: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserExited', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_EXITED,
            payload: {
              channel,
              user
            }
          });
        },
        onUserMuted: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserMuted', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_MUTED,
            payload: {
              channel,
              user
            }
          });
        },
        onUserUnmuted: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserUnmuted', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_UNMUTED,
            payload: {
              channel,
              user
            }
          });
        },
        onUserBanned: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserBanned', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_BANNED,
            payload: {
              channel,
              user,
              currentUser: sdk === null || sdk === void 0 ? void 0 : sdk.currentUser
            }
          });
        },
        onUserUnbanned: (channel, user) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onUserUnbanned', {
            channelUrl,
            user
          });
          messagesDispatcher({
            type: ON_USER_UNBANNED,
            payload: {
              channel,
              user
            }
          });
        },
        onChannelFrozen: channel => {
          logger.info('OpenChannel | useHandleChannelEvents: onChannelFrozen', channel);
          messagesDispatcher({
            type: ON_CHANNEL_FROZEN,
            payload: channel
          });
        },
        onChannelUnfrozen: channel => {
          logger.info('OpenChannel | useHandleChannelEvents: onChannelUnfrozen', channel);
          messagesDispatcher({
            type: ON_CHANNEL_UNFROZEN,
            payload: channel
          });
        },
        onChannelChanged: channel => {
          logger.info('OpenChannel | useHandleChannelEvents: onChannelChanged', channel);
          messagesDispatcher({
            type: ON_CHANNEL_CHANGED,
            payload: channel
          });
        },
        onMetaDataCreated: (channel, metaData) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaDataCreated', {
            channelUrl,
            metaData
          });
          messagesDispatcher({
            type: ON_META_DATA_CREATED,
            payload: {
              channel,
              metaData
            }
          });
        },
        onMetaDataUpdated: (channel, metaData) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaDataUpdated', {
            channelUrl,
            metaData
          });
          messagesDispatcher({
            type: ON_META_DATA_UPDATED,
            payload: {
              channel,
              metaData
            }
          });
        },
        onMetaDataDeleted: (channel, metaDataKeys) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaDataDeleted', {
            channelUrl,
            metaDataKeys
          });
          messagesDispatcher({
            type: ON_META_DATA_DELETED,
            payload: {
              channel,
              metaDataKeys
            }
          });
        },
        onMetaCounterCreated: (channel, metaCounter) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaCountersCreated', {
            channelUrl,
            metaCounter
          });
          messagesDispatcher({
            type: ON_META_COUNTERS_CREATED,
            payload: {
              channel,
              metaCounter
            }
          });
        },
        onMetaCounterUpdated: (channel, metaCounter) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaCountersUpdated', {
            channelUrl,
            metaCounter
          });
          messagesDispatcher({
            type: ON_META_COUNTERS_UPDATED,
            payload: {
              channel,
              metaCounter
            }
          });
        },
        onMetaCounterDeleted: (channel, metaCounterKeys) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMetaCountersDeleted', {
            channelUrl,
            metaCounterKeys
          });
          messagesDispatcher({
            type: ON_META_COUNTERS_DELETED,
            payload: {
              channel,
              metaCounterKeys
            }
          });
        },
        onMentionReceived: (channel, message) => {
          const channelUrl = channel === null || channel === void 0 ? void 0 : channel.url;
          logger.info('OpenChannel | useHandleChannelEvents: onMentionReceived', {
            channelUrl,
            message
          });
          messagesDispatcher({
            type: ON_MENTION_RECEIVED,
            payload: {
              channel,
              message
            }
          });
        },
        onChannelDeleted: (channelUrl, channelType) => {
          if (channelType === ChannelType.OPEN && (currentOpenChannel === null || currentOpenChannel === void 0 ? void 0 : currentOpenChannel.url) === channelUrl) {
            messagesDispatcher({
              type: ON_CHANNEL_DELETED,
              payload: channelUrl
            });
          }
        }
      };
      const ChannelHandler = new OpenChannelHandler(channelHandlerParams);
      sdk === null || sdk === void 0 ? void 0 : (_sdk$openChannel2 = sdk.openChannel) === null || _sdk$openChannel2 === void 0 ? void 0 : _sdk$openChannel2.addOpenChannelHandler(messageReceiverId, ChannelHandler);
    }
    return () => {
      var _sdk$openChannel3;
      if (sdk !== null && sdk !== void 0 && (_sdk$openChannel3 = sdk.openChannel) !== null && _sdk$openChannel3 !== void 0 && _sdk$openChannel3.removeOpenChannelHandler) {
        logger.info('OpenChannel | useHandleChannelEvents: Removing message receiver handler', messageReceiverId);
        sdk.openChannel.removeOpenChannelHandler(messageReceiverId);
      }
    };
  }, [currentOpenChannel]);
}

function useInitialMessagesFetch(_ref, _ref2) {
  let {
    currentOpenChannel,
    userFilledMessageListParams
  } = _ref;
  let {
    logger,
    messagesDispatcher,
    scrollRef
  } = _ref2;
  useEffect(() => {
    logger.info('OpenChannel | useInitialMessagesFetch: Setup started', currentOpenChannel);
    messagesDispatcher({
      type: RESET_MESSAGES,
      payload: null
    });
    if (currentOpenChannel && currentOpenChannel.getMessagesByTimestamp) {
      const messageListParams = {
        nextResultSize: 0,
        prevResultSize: 30,
        isInclusive: true,
        includeReactions: false
      };
      if (userFilledMessageListParams) {
        Object.keys(userFilledMessageListParams).forEach(key => {
          messageListParams[key] = userFilledMessageListParams[key];
        });
        logger.info('OpenChannel | useInitialMessagesFetch: Used customizedMessageListParams');
      }
      logger.info('OpenChannel | useInitialMessagesFetch: Fetching messages', {
        currentOpenChannel,
        messageListParams
      });
      messagesDispatcher({
        type: GET_PREV_MESSAGES_START,
        payload: null
      });
      currentOpenChannel.getMessagesByTimestamp(new Date().getTime(), messageListParams).then(messages => {
        logger.info('OpenChannel | useInitialMessagesFetch: Fetching messages succeeded', messages);
        const hasMore = messages && messages.length > 0;
        const lastMessageTimestamp = hasMore ? messages[0].createdAt : null;
        messagesDispatcher({
          type: GET_PREV_MESSAGES_SUCESS,
          payload: {
            currentOpenChannel,
            messages,
            hasMore,
            lastMessageTimestamp
          }
        });
        setTimeout(() => {
          scrollIntoLast(0, scrollRef);
        });
      }).catch(error => {
        logger.error('OpenChannel | useInitialMessagesFetch: Fetching messages failed', error);
        messagesDispatcher({
          type: GET_PREV_MESSAGES_FAIL,
          payload: {
            currentOpenChannel,
            messages: [],
            hasMore: false,
            lastMessageTimestamp: 0
          }
        });
      });
    }
  }, [currentOpenChannel, userFilledMessageListParams]);
}

function useScrollCallback(_ref, _ref2) {
  let {
    currentOpenChannel,
    lastMessageTimestamp,
    fetchMore
  } = _ref;
  let {
    sdk,
    logger,
    messagesDispatcher,
    hasMore,
    userFilledMessageListParams
  } = _ref2;
  return useCallback(callback => {
    if (fetchMore && hasMore) {
      logger.info('OpenChannel | useScrollCallback: start');
      const messageListParams = {
        prevResultSize: 30,
        includeReactions: false,
        nextResultSize: 0
      };
      if (userFilledMessageListParams) {
        Object.keys(userFilledMessageListParams).forEach(key => {
          messageListParams[key] = userFilledMessageListParams[key];
        });
        logger.info('OpenChannel | useScrollCallback: Used userFilledMessageListParams', userFilledMessageListParams);
      }
      logger.info('OpenChannel | useScrollCallback: Fetching messages', {
        currentOpenChannel,
        messageListParams
      });
      currentOpenChannel.getMessagesByTimestamp(lastMessageTimestamp || new Date().getTime(), messageListParams).then(messages => {
        logger.info('OpenChannel | useScrollCallback: Fetching messages succeeded', messages);
        const hasMore = messages && messages.length > 0;
        const lastMessageTimestamp = hasMore ? messages[0].createdAt : null;
        messagesDispatcher({
          type: GET_PREV_MESSAGES_SUCESS,
          payload: {
            currentOpenChannel,
            messages,
            hasMore,
            lastMessageTimestamp
          }
        });
        setTimeout(() => {
          callback();
        });
      }).catch(error => {
        logger.error('OpenChannel | useScrollCallback: Fetching messages failed', error);
        messagesDispatcher({
          type: GET_PREV_MESSAGES_FAIL,
          payload: {
            currentOpenChannel,
            messages: [],
            hasMore: false,
            lastMessageTimestamp: 0
          }
        });
      });
    }
  }, [currentOpenChannel, lastMessageTimestamp, fetchMore, sdk]);
}

function useCheckScrollBottom(_ref, _ref2) {
  let {
    conversationScrollRef
  } = _ref;
  let {
    logger
  } = _ref2;
  return useCallback(() => {
    let isBottom = true;
    if (conversationScrollRef && conversationScrollRef !== null && conversationScrollRef !== void 0 && conversationScrollRef.current) {
      try {
        const conversationScroll = conversationScrollRef.current;
        isBottom = conversationScroll.scrollHeight <= conversationScroll.scrollTop + conversationScroll.clientHeight;
      } catch (error) {
        logger.error('OpenChannel | useCheckScrollBottom', error);
      }
    }
    return isBottom;
  }, [conversationScrollRef]);
}

function useSendMessageCallback(_ref, _ref2) {
  let {
    currentOpenChannel,
    onBeforeSendUserMessage,
    checkScrollBottom,
    messageInputRef
  } = _ref;
  let {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef
  } = _ref2;
  return useCallback(() => {
    if (sdk) {
      const text = messageInputRef.current.innerText;
      const createParamsDefault = txt => {
        const message = txt;
        const params = {
          message: message
        };
        return params;
      };
      const createCustomParams = onBeforeSendUserMessage && typeof onBeforeSendUserMessage === 'function';
      if (createCustomParams) {
        logger.info('OpenChannel | useSendMessageCallback: Creating params using onBeforeSendUserMessage', onBeforeSendUserMessage);
      }
      const params = onBeforeSendUserMessage ? onBeforeSendUserMessage(text) : createParamsDefault(text);
      logger.info('OpenChannel | useSendMessageCallback: Sending message has started', params);
      const isBottom = checkScrollBottom();
      let pendingMsg = null;
      currentOpenChannel.sendUserMessage(params).onPending(pendingMessage => {
        messagesDispatcher({
          type: SENDING_MESSAGE_START,
          payload: {
            message: pendingMessage,
            channel: currentOpenChannel
          }
        });
        pendingMsg = pendingMessage;
      }).onSucceeded(message => {
        logger.info('OpenChannel | useSendMessageCallback: Sending message succeeded', message);
        messagesDispatcher({
          type: SENDING_MESSAGE_SUCCEEDED,
          payload: message
        });
        if (isBottom) {
          setTimeout(() => {
            scrollIntoLast(0, scrollRef);
          });
        }
      }).onFailed(error => {
        logger.warning('OpenChannel | useSendMessageCallback: Sending message failed', error);
        messagesDispatcher({
          type: SENDING_MESSAGE_FAILED,
          payload: pendingMsg
        });
        // https://sendbird.com/docs/chat/v3/javascript/guides/error-codes#2-server-error-codes
        // TODO: Do we need to handle the error cases?
        // @ts-ignore
        if ((error === null || error === void 0 ? void 0 : error.code) === 900041) {
          messagesDispatcher({
            type: ON_USER_MUTED,
            payload: {
              channel: currentOpenChannel,
              user: sdk.currentUser
            }
          });
        }
      });
    }
  }, [currentOpenChannel, onBeforeSendUserMessage, checkScrollBottom, messageInputRef]);
}

function useFileUploadCallback(_ref, _ref2) {
  let {
    currentOpenChannel,
    checkScrollBottom,
    imageCompression = {},
    onBeforeSendFileMessage
  } = _ref;
  let {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef
  } = _ref2;
  return useCallback(file => {
    if (sdk) {
      const {
        compressionRate,
        resizingWidth,
        resizingHeight
      } = imageCompression;
      const createCustomParams = onBeforeSendFileMessage && typeof onBeforeSendFileMessage === 'function';
      const compressibleFileType = file.type === 'image/jpg' || file.type === 'image/png' || file.type === 'image/jpeg';
      const compressibleRatio = compressionRate > 0 && compressionRate < 1;
      // pxToNumber returns null if values are invalid
      const compressibleDiamensions = pxToNumber(resizingWidth) || pxToNumber(resizingHeight);
      const canCompressImage = compressibleFileType && (compressibleRatio || compressibleDiamensions);
      const createParamsDefault = file_ => {
        const params = {};
        params.file = file_;
        return params;
      };
      if (canCompressImage) {
        // Using image compression
        try {
          const image = document.createElement('img');
          image.src = URL.createObjectURL(file);
          image.onload = () => {
            URL.revokeObjectURL(image.src);
            const canvas = document.createElement('canvas');
            const imageWidth = image.naturalWidth || image.width;
            const imageHeight = image.naturalHeight || image.height;
            let targetWidth = pxToNumber(resizingWidth) || imageWidth;
            let targetHeight = pxToNumber(resizingHeight) || imageHeight;

            // In canvas.toBlob(callback, mimeType, qualityArgument)
            // qualityArgument doesnt work
            // so in case compressibleDiamensions are not present, we use ratio
            if (file.type === 'image/png' && !compressibleDiamensions) {
              targetWidth *= compressionRate;
              targetHeight *= compressionRate;
            }
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            const context = canvas.getContext('2d');
            context.drawImage(image, 0, 0, targetWidth, targetHeight);
            context.canvas.toBlob(newImageBlob => {
              const compressedFile = new File([newImageBlob], file.name, {
                type: file.type
              });
              if (createCustomParams) {
                logger.info('OpenChannel | useFileUploadCallback: Creating params using onBeforeSendFileMessage', onBeforeSendFileMessage);
              }
              const params = onBeforeSendFileMessage ? onBeforeSendFileMessage(compressedFile) : createParamsDefault(compressedFile);
              logger.info('OpenChannel | useFileUploadCallback: Uploading file message start', params);
              const isBottom = checkScrollBottom();
              currentOpenChannel.sendFileMessage(params).onPending(pendingMessage => {
                messagesDispatcher({
                  type: SENDING_MESSAGE_START,
                  payload: {
                    message: _objectSpread2(_objectSpread2({}, pendingMessage), {}, {
                      url: URL.createObjectURL(file),
                      // pending thumbnail message seems to be failed
                      requestState: 'pending'
                    }),
                    channel: currentOpenChannel
                  }
                });
              }).onSucceeded(message => {
                logger.info('OpenChannel | useFileUploadCallback: Sending message succeeded', message);
                messagesDispatcher({
                  type: SENDING_MESSAGE_SUCCEEDED,
                  payload: message
                });
                if (isBottom) {
                  setTimeout(() => {
                    scrollIntoLast(0, scrollRef);
                  });
                }
              }).onFailed((error, message) => {
                logger.error('OpenChannel | useFileUploadCallback: Sending file message failed', {
                  message,
                  error
                });
                // @ts-ignore
                message.localUrl = URL.createObjectURL(file);
                // @ts-ignore
                message.file = file;
                messagesDispatcher({
                  type: SENDING_MESSAGE_FAILED,
                  payload: message
                });
              });
            }, file.type, compressionRate);
          };
        } catch (error) {
          logger.warning('OpenChannel | useFileUploadCallback: Sending file message with image compression failed', error);
        }
      } else {
        // Not using image compression
        if (createCustomParams) {
          logger.info('OpenChannel | useFileUploadCallback: Creating params using onBeforeSendFileMessage', onBeforeSendFileMessage);
        }
        const params = onBeforeSendFileMessage ? onBeforeSendFileMessage(file) : createParamsDefault(file);
        logger.info('OpenChannel | useFileUploadCallback: Uploading file message start', params);
        const isBottom = checkScrollBottom();
        currentOpenChannel.sendFileMessage(params).onPending(pendingMessage => {
          messagesDispatcher({
            type: SENDING_MESSAGE_START,
            payload: {
              message: _objectSpread2(_objectSpread2({}, pendingMessage), {}, {
                url: URL.createObjectURL(file),
                // pending thumbnail message seems to be failed
                requestState: 'pending'
              }),
              channel: currentOpenChannel
            }
          });
        }).onSucceeded(message => {
          logger.info('OpenChannel | useFileUploadCallback: Sending message succeeded', message);
          messagesDispatcher({
            type: SENDING_MESSAGE_SUCCEEDED,
            payload: message
          });
          if (isBottom) {
            setTimeout(() => {
              scrollIntoLast(0, scrollRef);
            });
          }
        }).onFailed((error, message) => {
          logger.error('OpenChannel | useFileUploadCallback: Sending file message failed', {
            message,
            error
          });
          // @ts-ignore
          message.localUrl = URL.createObjectURL(file);
          // @ts-ignore
          message.file = file;
          messagesDispatcher({
            type: SENDING_MESSAGE_FAILED,
            payload: message
          });
        });
      }
    }
  }, [currentOpenChannel, onBeforeSendFileMessage, checkScrollBottom, imageCompression]);
}

function useUpdateMessageCallback(_ref, _ref2) {
  let {
    currentOpenChannel,
    onBeforeSendUserMessage
  } = _ref;
  let {
    logger,
    messagesDispatcher
  } = _ref2;
  return useCallback((messageId, text, callback) => {
    const createParamsDefault = txt => {
      const params = {
        message: txt
      };
      return params;
    };
    if (onBeforeSendUserMessage && typeof onBeforeSendUserMessage === 'function') {
      logger.info('OpenChannel | useUpdateMessageCallback: Creating params using onBeforeUpdateUserMessage');
    }
    const params = onBeforeSendUserMessage ? onBeforeSendUserMessage(text) : createParamsDefault(text);
    currentOpenChannel.updateUserMessage(messageId, params).then(message => {
      if (callback) {
        callback();
      }
      logger.info('OpenChannel | useUpdateMessageCallback: Updating message succeeded', {
        message,
        params
      });
      messagesDispatcher({
        type: ON_MESSAGE_UPDATED,
        payload: {
          channel: currentOpenChannel,
          message
        }
      });
    });
  }, [currentOpenChannel, onBeforeSendUserMessage]);
}

function useDeleteMessageCallback(_ref, _ref2) {
  let {
    currentOpenChannel
  } = _ref;
  let {
    logger,
    messagesDispatcher
  } = _ref2;
  return useCallback((message, callback) => {
    logger.info('OpenChannel | useDeleteMessageCallback: Deleting message', message);
    const {
      sendingStatus
    } = message;
    logger.info('OpenChannel | useDeleteMessageCallback: Deleting message requestState', sendingStatus);
    if (sendingStatus === 'failed' || sendingStatus === 'pending') {
      logger.info('OpenChannel | useDeleteMessageCallback: Deleted message from local', message);
      messagesDispatcher({
        type: ON_MESSAGE_DELETED_BY_REQ_ID,
        payload: message.reqId
      });
      if (callback) {
        callback();
      }
    } else {
      if (!(message.messageType === 'file' || message.messageType === 'user')) {
        return;
      }
      const messageToDelete = message;
      currentOpenChannel.deleteMessage(messageToDelete).then(() => {
        logger.info('OpenChannel | useDeleteMessageCallback: Deleting message on server', sendingStatus);
        if (callback) {
          callback();
        }
        logger.info('OpenChannel | useDeleteMessageCallback: Deleting message succeeded', message);
        messagesDispatcher({
          type: ON_MESSAGE_DELETED,
          payload: {
            channel: currentOpenChannel,
            messageId: message.messageId
          }
        });
      }).catch(error => {
        logger.warning('OpenChannel | useDeleteMessageCallback: Deleting message failed', error);
      });
    }
  }, [currentOpenChannel]);
}

function useResendMessageCallback(_ref, _ref2) {
  let {
    currentOpenChannel
  } = _ref;
  let {
    logger,
    messagesDispatcher
  } = _ref2;
  return useCallback(failedMessage => {
    logger.info('OpenChannel | useResendMessageCallback: Resending message has started', failedMessage);
    // eslint-disable-next-line no-param-reassign
    const {
      messageType,
      file
    } = failedMessage;
    if (failedMessage && typeof failedMessage.isResendable === 'function' && failedMessage.isResendable) {
      // eslint-disable-next-line no-param-reassign
      failedMessage.requestState = 'pending';
      messagesDispatcher({
        type: RESENDING_MESSAGE_START,
        payload: {
          channel: currentOpenChannel,
          message: failedMessage
        }
      });

      // userMessage
      if (messageType === 'user' && failedMessage.messageType === 'user') {
        currentOpenChannel.resendUserMessage(failedMessage).then(message => {
          logger.info('OpenChannel | useResendMessageCallback: Reseding message succeeded', message);
          messagesDispatcher({
            type: SENDING_MESSAGE_SUCCEEDED,
            payload: message
          });
        }).catch(error => {
          logger.warning('OpenChannel | useResendMessageCallback: Resending message failed', error);
          // eslint-disable-next-line no-param-reassign
          failedMessage.requestState = 'failed';
          messagesDispatcher({
            type: SENDING_MESSAGE_FAILED,
            payload: failedMessage
          });
        });
      }

      // fileMessage
      if (messageType === 'file' && failedMessage.messageType === 'file') {
        currentOpenChannel.resendFileMessage(failedMessage, file).then(message => {
          logger.info('OpenChannel | useResendMessageCallback: Resending file message succeeded', message);
          messagesDispatcher({
            type: SENDING_MESSAGE_SUCCEEDED,
            payload: message
          });
        }).catch(error => {
          logger.warning('OpenChannel | useResendMessageCallback: Resending file message failed', error);
          // eslint-disable-next-line no-param-reassign
          failedMessage.requestState = 'failed';
          messagesDispatcher({
            type: SENDING_MESSAGE_FAILED,
            payload: failedMessage
          });
        });
      }
    } else {
      // to alert user on console
      // eslint-disable-next-line no-console
      console.error('OpenChannel | useResendMessageCallback: Message is not resendable');
      logger.warning('OpenChannel | useResendMessageCallback: Message is not resendable', failedMessage);
    }
  }, [currentOpenChannel]);
}

const THROTTLE_TIMER = 5000;

// to trim message list so that we wont keep thousands of messages in memory
// We are throttling here; not debouncing
// it will be called once very 5 sec if messagesLength, messageLimit changes
// we check if messagesLength > messageLimit before dispatching action
function useTrimMessageList(_ref, _ref2) {
  let {
    messagesLength,
    messageLimit
  } = _ref;
  let {
    messagesDispatcher,
    logger
  } = _ref2;
  const [inProgress, setInProgress] = useState(false);
  useEffect(() => {
    if (inProgress) {
      return;
    }
    if (typeof messagesLength === 'number' && messagesLength > messageLimit) {
      logger.info('Trimming MessageList');
      messagesDispatcher({
        type: TRIM_MESSAGE_LIST,
        payload: {
          messageLimit
        }
      });
    }
    setInProgress(true);
    setTimeout(() => {
      setInProgress(false);
    }, THROTTLE_TIMER);
  }, [messagesLength, messageLimit]);
}

const OpenChannelContext = /*#__PURE__*/React__default.createContext(undefined);
const OpenChannelProvider = props => {
  var _globalStore$stores, _globalStore$stores$s, _globalStore$stores2, _globalStore$stores2$, _globalStore$stores3, _globalStore$stores3$, _props$disableUserPro;
  const {
    channelUrl,
    children,
    isMessageGroupingEnabled = true,
    queries,
    onBeforeSendUserMessage,
    messageLimit,
    onBeforeSendFileMessage,
    onChatHeaderActionClick,
    onBackClick
  } = props;

  // We didn't decide to support fetching participant list
  const fetchingParticipants = false;
  const globalStore = useSendbirdStateContext();
  const sdk = globalStore === null || globalStore === void 0 ? void 0 : (_globalStore$stores = globalStore.stores) === null || _globalStore$stores === void 0 ? void 0 : (_globalStore$stores$s = _globalStore$stores.sdkStore) === null || _globalStore$stores$s === void 0 ? void 0 : _globalStore$stores$s.sdk;
  const sdkInit = globalStore === null || globalStore === void 0 ? void 0 : (_globalStore$stores2 = globalStore.stores) === null || _globalStore$stores2 === void 0 ? void 0 : (_globalStore$stores2$ = _globalStore$stores2.sdkStore) === null || _globalStore$stores2$ === void 0 ? void 0 : _globalStore$stores2$.initialized;
  const user = globalStore === null || globalStore === void 0 ? void 0 : (_globalStore$stores3 = globalStore.stores) === null || _globalStore$stores3 === void 0 ? void 0 : (_globalStore$stores3$ = _globalStore$stores3.userStore) === null || _globalStore$stores3$ === void 0 ? void 0 : _globalStore$stores3$.user;
  const config = globalStore === null || globalStore === void 0 ? void 0 : globalStore.config;
  const {
    userId,
    isOnline,
    logger,
    pubSub,
    imageCompression
  } = config;

  // hook variables
  const [messagesStore, messagesDispatcher] = useReducer(reducer, initialState);
  const {
    allMessages,
    loading,
    initialized,
    currentOpenChannel,
    isInvalid,
    hasMore,
    lastMessageTimestamp,
    operators,
    bannedParticipantIds,
    mutedParticipantIds
  } = messagesStore;
  // ref
  const messageInputRef = useRef(null); // useSendMessageCallback
  const conversationScrollRef = useRef(null); // useScrollAfterSendMessageCallback

  // const
  const userFilledMessageListParams = queries === null || queries === void 0 ? void 0 : queries.messageListParams;
  const disabled = !initialized || !isOnline || isDisabledBecauseFrozen(currentOpenChannel, userId) || isDisabledBecauseMuted(mutedParticipantIds, userId);

  // useMemo
  const amIBanned = useMemo(() => {
    return bannedParticipantIds.indexOf(user.userId) >= 0;
  }, [channelUrl, bannedParticipantIds, user]);
  const amIMuted = useMemo(() => {
    return mutedParticipantIds.indexOf(user.userId) >= 0;
  }, [channelUrl, mutedParticipantIds, user]);
  const amIOperator = useMemo(() => {
    return operators.map(operator => operator.userId).indexOf(user.userId) >= 0;
  }, [channelUrl, operators, user]);

  // use hooks
  useSetChannel({
    channelUrl,
    sdkInit,
    fetchingParticipants,
    userId,
    currentOpenChannel
  }, {
    sdk,
    logger,
    messagesDispatcher
  });
  const checkScrollBottom = useCheckScrollBottom({
    conversationScrollRef
  }, {
    logger
  });
  useHandleChannelEvents({
    currentOpenChannel,
    checkScrollBottom
  }, {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef: conversationScrollRef
  });
  useInitialMessagesFetch({
    currentOpenChannel,
    userFilledMessageListParams
  }, {
    logger,
    messagesDispatcher,
    scrollRef: conversationScrollRef
  });
  const fetchMore = shouldFetchMore(allMessages === null || allMessages === void 0 ? void 0 : allMessages.length, messageLimit);
  // donot fetch more for streaming
  const onScroll = useScrollCallback({
    currentOpenChannel,
    lastMessageTimestamp,
    fetchMore
  }, {
    sdk,
    logger,
    messagesDispatcher,
    hasMore,
    userFilledMessageListParams
  });
  const handleSendMessage = useSendMessageCallback({
    currentOpenChannel,
    onBeforeSendUserMessage,
    checkScrollBottom,
    messageInputRef
  }, {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef: conversationScrollRef
  });
  const handleFileUpload = useFileUploadCallback({
    currentOpenChannel,
    onBeforeSendFileMessage,
    checkScrollBottom,
    imageCompression
  }, {
    sdk,
    logger,
    messagesDispatcher,
    scrollRef: conversationScrollRef
  });
  const updateMessage = useUpdateMessageCallback({
    currentOpenChannel,
    onBeforeSendUserMessage
  }, {
    logger,
    messagesDispatcher
  });
  const deleteMessage = useDeleteMessageCallback({
    currentOpenChannel
  }, {
    logger,
    messagesDispatcher
  });
  const resendMessage = useResendMessageCallback({
    currentOpenChannel
  }, {
    logger,
    messagesDispatcher
  });
  useTrimMessageList({
    messagesLength: allMessages === null || allMessages === void 0 ? void 0 : allMessages.length,
    messageLimit
  }, {
    messagesDispatcher,
    logger
  });

  // handle API calls from withSendbird
  useEffect(() => {
    const subscriber = new Map();
    if (!pubSub || !pubSub.subscribe) {
      return;
    }
    subscriber.set(PUBSUB_TOPICS.SEND_USER_MESSAGE, pubSub.subscribe(PUBSUB_TOPICS.SEND_USER_MESSAGE, msg => {
      const {
        channel,
        message
      } = msg;
      scrollIntoLast(0, conversationScrollRef);
      if (channel && channelUrl === (channel === null || channel === void 0 ? void 0 : channel.url)) {
        messagesDispatcher({
          type: SENDING_MESSAGE_SUCCEEDED,
          payload: message
        });
      }
    }));
    subscriber.set(PUBSUB_TOPICS.SEND_MESSAGE_START, pubSub.subscribe(PUBSUB_TOPICS.SEND_MESSAGE_START, msg => {
      const {
        channel,
        message
      } = msg;
      if (channel && channelUrl === (channel === null || channel === void 0 ? void 0 : channel.url)) {
        messagesDispatcher({
          type: SENDING_MESSAGE_START,
          payload: {
            message,
            channel
          }
        });
      }
    }));
    subscriber.set(PUBSUB_TOPICS.SEND_FILE_MESSAGE, pubSub.subscribe(PUBSUB_TOPICS.SEND_FILE_MESSAGE, msg => {
      const {
        channel,
        message
      } = msg;
      scrollIntoLast(0, conversationScrollRef);
      if (channel && channelUrl === (channel === null || channel === void 0 ? void 0 : channel.url)) {
        messagesDispatcher({
          type: SENDING_MESSAGE_SUCCEEDED,
          payload: {
            message,
            channel
          }
        });
      }
    }));
    subscriber.set(PUBSUB_TOPICS.UPDATE_USER_MESSAGE, pubSub.subscribe(PUBSUB_TOPICS.UPDATE_USER_MESSAGE, msg => {
      const {
        channel,
        message,
        fromSelector
      } = msg;
      if (fromSelector && channel && channelUrl === (channel === null || channel === void 0 ? void 0 : channel.url)) {
        messagesDispatcher({
          type: ON_MESSAGE_UPDATED,
          payload: {
            channel,
            message
          }
        });
      }
    }));
    subscriber.set(PUBSUB_TOPICS.DELETE_MESSAGE, pubSub.subscribe(PUBSUB_TOPICS.DELETE_MESSAGE, msg => {
      const {
        channel,
        messageId
      } = msg;
      if (channel && channelUrl === (channel === null || channel === void 0 ? void 0 : channel.url)) {
        messagesDispatcher({
          type: ON_MESSAGE_DELETED,
          payload: messageId
        });
      }
    }));
    return () => {
      if (subscriber) {
        subscriber.forEach(s => {
          try {
            s.remove();
          } catch (_unused) {
            //
          }
        });
      }
    };
  }, [channelUrl, sdkInit]);
  return /*#__PURE__*/React__default.createElement(OpenChannelContext.Provider, {
    value: {
      // props
      channelUrl,
      children,
      isMessageGroupingEnabled,
      queries,
      onBeforeSendUserMessage,
      messageLimit,
      onBeforeSendFileMessage,
      onChatHeaderActionClick,
      onBackClick,
      // store
      allMessages,
      loading,
      initialized,
      currentOpenChannel,
      isInvalid,
      hasMore,
      lastMessageTimestamp,
      operators,
      bannedParticipantIds,
      mutedParticipantIds,
      // derived/utils
      messageInputRef,
      conversationScrollRef,
      disabled,
      amIBanned,
      amIMuted,
      amIOperator,
      checkScrollBottom,
      fetchMore,
      onScroll,
      handleSendMessage,
      handleFileUpload,
      updateMessage,
      deleteMessage,
      resendMessage
    }
  }, /*#__PURE__*/React__default.createElement(UserProfileProvider, {
    isOpenChannel: true,
    renderUserProfile: props === null || props === void 0 ? void 0 : props.renderUserProfile,
    disableUserProfile: (_props$disableUserPro = props === null || props === void 0 ? void 0 : props.disableUserProfile) !== null && _props$disableUserPro !== void 0 ? _props$disableUserPro : config === null || config === void 0 ? void 0 : config.disableUserProfile
  }, children));
};
const useOpenChannelContext = () => React__default.useContext(OpenChannelContext);

export { OpenChannelProvider as O, compareMessagesForGrouping as c, kFormatter as k, useOpenChannelContext as u };
//# sourceMappingURL=OpenChannelProvider-1efcabea.js.map
