import { _ as _objectSpread2, a as _defineProperty } from './_rollupPluginBabelHelpers-0bc76382.js';
import React__default, { useLayoutEffect, useState, useEffect, useCallback, useContext, createContext, useMemo, useReducer } from 'react';
import { SendbirdSdkContext } from './withSendbird.js';
import cssVars from 'css-vars-ponyfill';
import { K } from './index.module-9202ebbd.js';
import { U as USER_ACTIONS } from './actionTypes-45ec82e6.js';
import SendbirdChat, { ConnectionHandler } from '@sendbird/chat';
import { u as uuidv4 } from './uuid-1f1bbd9c.js';
import { OpenChannelModule } from '@sendbird/chat/openChannel';
import { GroupChannelModule } from '@sendbird/chat/groupChannel';
import { i as isTextuallyNull } from './index-e2601165.js';
import { V as VoicePlayerProvider } from './index-d847a382.js';
import { VoiceRecorderProvider } from './VoiceRecorder/context.js';
import { L as LocalizationProvider } from './LocalizationContext-57b46f6c.js';
import { M as MediaQueryProvider } from './MediaQueryContext-fbe7af77.js';
import { g as getStringSet } from './stringSet-7a8ce1ce.js';
import { V as VOICE_RECORDER_DEFAULT_MAX, a as VOICE_RECORDER_DEFAULT_MIN } from './consts-3c0ff1ed.js';
import './utils/message/getOutgoingMessageState.js';
import './useSendbirdStateContext.js';
import './index-865112db.js';

const isEmpty = obj => {
  if (obj === null || obj === undefined) {
    return true;
  }
  for (const prop in obj) {
    if (obj.hasOwnProperty(prop)) {
      return false;
    }
  }
  return JSON.stringify(obj) === JSON.stringify({});
};
const useTheme = overrides => {
  useLayoutEffect(() => {
    if (!isEmpty(overrides)) {
      cssVars({
        variables: _objectSpread2(_objectSpread2({}, {
          '--sendbird-dark-primary-500': '#4d2aa6',
          '--sendbird-dark-primary-400': '#6440C4',
          '--sendbird-dark-primary-300': '#7B53EF',
          '--sendbird-dark-primary-200': '#9E8CF5',
          '--sendbird-dark-primary-100': '#E2DFFF',
          '--sendbird-dark-secondary-500': '#007A7A',
          '--sendbird-dark-secondary-400': '#189A8D',
          '--sendbird-dark-secondary-300': '#2EBA9F',
          '--sendbird-dark-secondary-200': '#6FD6BE',
          '--sendbird-dark-secondary-100': '#AEF2DC',
          '--sendbird-dark-information-100': '#b2d9ff',
          '--sendbird-dark-error-500': '#A30E2D',
          '--sendbird-dark-error-400': '#C11F41',
          '--sendbird-dark-error-300': '#E53157',
          '--sendbird-dark-error-200': '#FF6183',
          '--sendbird-dark-error-100': '#FFABBD',
          '--sendbird-dark-background-700': '#000000',
          '--sendbird-dark-background-600': '#161616',
          '--sendbird-dark-background-500': '#2C2C2C',
          '--sendbird-dark-background-400': '#393939',
          '--sendbird-dark-background-300': '#A8A8A8',
          '--sendbird-dark-background-200': '#D9D9D9',
          '--sendbird-dark-background-100': '#F0F0F0',
          '--sendbird-dark-background-50': '#FFFFFF',
          '--sendbird-dark-overlay': 'rgba(0, 0, 0, 0.32)',
          '--sendbird-dark-onlight-01': 'rgba(0, 0, 0, 0.88)',
          '--sendbird-dark-onlight-02': 'rgba(0, 0, 0, 0.50)',
          '--sendbird-dark-onlight-03': 'rgba(0, 0, 0, 0.38)',
          '--sendbird-dark-onlight-04': 'rgba(0, 0, 0, 0.12)',
          '--sendbird-dark-ondark-01': 'rgba(255, 255, 255, 0.88)',
          '--sendbird-dark-ondark-02': 'rgba(255, 255, 255, 0.50)',
          '--sendbird-dark-ondark-03': 'rgba(255, 255, 255, 0.38)',
          '--sendbird-dark-ondark-04': 'rgba(255, 255, 255, 0.12)',
          '--sendbird-dark-shadow-01': '0 1px 5px 0 rgba(33, 34, 66, 0.04), 0 0 3px 0 rgba(0, 0, 0, 0.08), 0 2px 1px 0 rgba(0, 0, 0, 0.12)',
          '--sendbird-dark-shadow-02': '0 3px 5px -3px rgba(33, 34, 66, 0.04), 0 3px 14px 2px rgba(0, 0, 0, 0.08), 0 8px 10px 1px rgba(0, 0, 0, 0.12)',
          '--sendbird-dark-shadow-03': '0 6px 10px -5px rgba(0, 0, 0, 0.04), 0 6px 30px 5px rgba(0, 0, 0, 0.08), 0 16px 24px 2px rgba(0, 0, 0, 0.12)',
          '--sendbird-dark-shadow-04': '0 9px 15px -7px rgba(0, 0, 0, 0.04), 0 9px 46px 8px rgba(0, 0, 0, 0.08), 0 24px 38px 3px rgba(0, 0, 0, 0.12)',
          '--sendbird-dark-shadow-message-input': '0 1px 5px 0 rgba(33, 34, 66, 0.12), 0 0 1px 0 rgba(33, 34, 66, 0.16), 0 2px 1px 0 rgba(33, 34, 66, 0.08), 0 1px 5px 0 rgba(0, 0, 0, 0.12)',
          '--sendbird-light-primary-500': '#4d2aa6',
          '--sendbird-light-primary-400': '#6440C4',
          '--sendbird-light-primary-300': '#7B53EF',
          '--sendbird-light-primary-200': '#9E8CF5',
          '--sendbird-light-primary-100': '#E2DFFF',
          '--sendbird-light-secondary-500': '#007A7A',
          '--sendbird-light-secondary-400': '#189A8D',
          '--sendbird-light-secondary-300': '#2EBA9F',
          '--sendbird-light-secondary-200': '#6FD6BE',
          '--sendbird-light-secondary-100': '#AEF2DC',
          '--sendbird-light-information-100': '#b2d9ff',
          '--sendbird-light-error-500': '#A30E2D',
          '--sendbird-light-error-400': '#C11F41',
          '--sendbird-light-error-300': '#E53157',
          '--sendbird-light-error-200': '#FF6183',
          '--sendbird-light-error-100': '#FFABBD',
          '--sendbird-light-background-700': '#000000',
          '--sendbird-light-background-600': '#161616',
          '--sendbird-light-background-500': '#2C2C2C',
          '--sendbird-light-background-400': '#393939',
          '--sendbird-light-background-300': '#A8A8A8',
          '--sendbird-light-background-200': '#D9D9D9',
          '--sendbird-light-background-100': '#F0F0F0',
          '--sendbird-light-background-50': ' #FFFFFF',
          '--sendbird-light-overlay': 'rgba(0, 0, 0, 0.32)',
          '--sendbird-light-onlight-01': 'rgba(0, 0, 0, 0.88)',
          '--sendbird-light-onlight-02': 'rgba(0, 0, 0, 0.50)',
          '--sendbird-light-onlight-03': 'rgba(0, 0, 0, 0.38)',
          '--sendbird-light-onlight-04': 'rgba(0, 0, 0, 0.12)',
          '--sendbird-light-ondark-01': 'rgba(255, 255, 255, 0.88)',
          '--sendbird-light-ondark-02': 'rgba(255, 255, 255, 0.50)',
          '--sendbird-light-ondark-03': 'rgba(255, 255, 255, 0.38)',
          '--sendbird-light-ondark-04': 'rgba(255, 255, 255, 0.12)',
          '--sendbird-light-shadow-01': '0 1px 5px 0 rgba(33, 34, 66, 0.04), 0 0 3px 0 rgba(0, 0, 0, 0.08), 0 2px 1px 0 rgba(0, 0, 0, 0.12)',
          '--sendbird-light-shadow-02': '0 3px 5px -3px rgba(33, 34, 66, 0.04), 0 3px 14px 2px rgba(0, 0, 0, 0.08), 0 8px 10px 1px rgba(0, 0, 0, 0.12)',
          '--sendbird-light-shadow-03': '0 6px 10px -5px rgba(0, 0, 0, 0.04), 0 6px 30px 5px rgba(0, 0, 0, 0.08), 0 16px 24px 2px rgba(0, 0, 0, 0.12)',
          '--sendbird-light-shadow-04': '0 9px 15px -7px rgba(0, 0, 0, 0.04), 0 9px 46px 8px rgba(0, 0, 0, 0.08), 0 24px 38px 3px rgba(0, 0, 0, 0.12)',
          '--sendbird-light-shadow-message-input': '0 1px 5px 0 rgba(33, 34, 66, 0.12), 0 0 1px 0 rgba(33, 34, 66, 0.16), 0 2px 1px 0 rgba(33, 34, 66, 0.08), 0 1px 5px 0 rgba(0, 0, 0, 0.12)'
        }), overrides)
      });
    }
  }, [overrides]);
};

const SDK_ACTIONS = {
  INIT_SDK: 'INIT_SDK',
  SET_SDK_LOADING: 'SET_SDK_LOADING',
  RESET_SDK: 'RESET_SDK',
  SDK_ERROR: 'SDK_ERROR'
};

const initialState$1 = {
  initialized: false,
  loading: false,
  sdk: {},
  error: false
};

function reducer$1(state, action) {
  return K(action).with({
    type: SDK_ACTIONS.SET_SDK_LOADING
  }, _ref => {
    let {
      payload
    } = _ref;
    return _objectSpread2(_objectSpread2({}, state), {}, {
      initialized: false,
      loading: payload
    });
  }).with({
    type: SDK_ACTIONS.SDK_ERROR
  }, () => {
    return _objectSpread2(_objectSpread2({}, state), {}, {
      initialized: false,
      loading: false,
      error: true
    });
  }).with({
    type: SDK_ACTIONS.INIT_SDK
  }, _ref2 => {
    let {
      payload
    } = _ref2;
    return {
      sdk: payload,
      initialized: true,
      loading: false,
      error: false
    };
  }).with({
    type: SDK_ACTIONS.RESET_SDK
  }, () => {
    return initialState$1;
  }).otherwise(() => {
    return state;
  });
}

const initialState = {
  initialized: false,
  loading: false,
  user: {}
};

function reducer(state, action) {
  return K(action).with({
    type: USER_ACTIONS.INIT_USER
  }, _ref => {
    let {
      payload
    } = _ref;
    return {
      initialized: true,
      loading: false,
      user: payload
    };
  }).with({
    type: USER_ACTIONS.RESET_USER
  }, () => {
    return initialState;
  }).with({
    type: USER_ACTIONS.UPDATE_USER_INFO
  }, _ref2 => {
    let {
      payload
    } = _ref2;
    return _objectSpread2(_objectSpread2({}, state), {}, {
      user: payload
    });
  }).otherwise(() => {
    return state;
  });
}

function useConnectionStatus(sdk, logger) {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() => {
    const uniqueHandlerId = uuidv4();
    try {
      logger.warning('sdk changed', uniqueHandlerId);
      const handler = new ConnectionHandler();
      handler.onDisconnected = () => {
        logger.warning('onDisconnected', {
          isOnline
        });
      };
      handler.onReconnectStarted = () => {
        setIsOnline(false);
        logger.warning('onReconnectStarted', {
          isOnline
        });
      };
      handler.onReconnectSucceeded = () => {
        setIsOnline(true);
        logger.warning('onReconnectSucceeded', {
          isOnline
        });
      };
      handler.onReconnectFailed = () => {
        sdk.reconnect();
        logger.warning('onReconnectFailed');
      };
      logger.info('Added ConnectionHandler', uniqueHandlerId);
      // workaround -> addConnectionHandler invalidates session handler
      // provided through configureSession
      if (sdk !== null && sdk !== void 0 && sdk.addConnectionHandler) {
        sdk.addConnectionHandler(uniqueHandlerId, handler);
      }
    } catch (_unused) {
      //
    }
    return () => {
      try {
        sdk.removeConnectionHandler(uniqueHandlerId);
        logger.info('Removed ConnectionHandler', uniqueHandlerId);
      } catch (_unused2) {
        //
      }
    };
  }, [sdk]);
  useEffect(() => {
    const tryReconnect = () => {
      try {
        logger.warning('Try reconnecting SDK');
        if (sdk.connectionState !== 'OPEN') {
          // connection is not broken yet
          sdk.reconnect();
        }
      } catch (_unused3) {
        //
      }
    };
    // addEventListener version
    window.addEventListener('online', tryReconnect);
    return () => {
      window.removeEventListener('online', tryReconnect);
    };
  }, [sdk]);

  // add offline-class to body
  useEffect(() => {
    const body = document.querySelector('body');
    if (!isOnline) {
      try {
        body.classList.add('sendbird__offline');
        logger.info('Added class sendbird__offline to body');
      } catch (e) {
        //
      }
    } else {
      try {
        body.classList.remove('sendbird__offline');
        logger.info('Removed class sendbird__offline from body');
      } catch (e) {
        //
      }
    }
  }, [isOnline]);
  return isOnline;
}

async function disconnectSdk(_ref) {
  let {
    sdkDispatcher,
    userDispatcher,
    sdk
  } = _ref;
  return new Promise(resolve => {
    sdkDispatcher({
      type: SDK_ACTIONS.SET_SDK_LOADING,
      payload: true
    });
    if (sdk !== null && sdk !== void 0 && sdk.disconnect) {
      sdk.disconnect().then(() => {
        sdkDispatcher({
          type: SDK_ACTIONS.RESET_SDK
        });
        userDispatcher({
          type: USER_ACTIONS.RESET_USER
        });
      }).finally(() => {
        resolve(true);
      });
    } else {
      resolve(true);
    }
  });
}

const APP_VERSION_STRING = '3.5.0-mobile-web-1';
const {
  INIT_SDK,
  SET_SDK_LOADING,
  RESET_SDK,
  SDK_ERROR
} = SDK_ACTIONS;
const {
  INIT_USER,
  UPDATE_USER_INFO,
  RESET_USER
} = USER_ACTIONS;
function getMissingParamError(_ref) {
  let {
    userId,
    appId
  } = _ref;
  return `SendbirdProvider | useConnect/setupConnection/Connection failed UserId: ${userId} or appId: ${appId} missing`;
}
function getConnectSbError(error) {
  return `SendbirdProvider | useConnect/setupConnection/Connection failed. ${(error === null || error === void 0 ? void 0 : error.code) || ''} ${(error === null || error === void 0 ? void 0 : error.message) || ''}`;
}
function setUpParams(_ref2) {
  let {
    appId,
    customApiHost,
    customWebSocketHost
  } = _ref2;
  const params = {
    appId,
    modules: [new GroupChannelModule(), new OpenChannelModule()]
  };
  if (customApiHost) {
    params['customApiHost'] = customApiHost;
  }
  if (customWebSocketHost) {
    params['customWebSocketHost'] = customWebSocketHost;
  }
  const newSdk = SendbirdChat.init(params);
  return newSdk;
}

// Steps
// 1. Check if minimum userID/appID is provided
//  1.a. If not, throw error > !reject
//  1.b. If yes, continue
// 2. Set up params with custom host if provided
// 3. Set up session handler if provided
// 4. Set up version
// 5. Connect to Sendbird -> either using user ID or (user ID + access token)
// 6. If connected, connectCbSucess
//  6.a check if nickname is to be updated -> no > !resolve immediately
//  6.b check if nickname is to be updated -> yes > update nickname > !resolve
// 7. If not connected, connectCbError > !reject
async function setUpConnection(_ref3) {
  let {
    logger,
    sdkDispatcher,
    userDispatcher,
    initDashboardConfigs,
    userId,
    appId,
    customApiHost,
    customWebSocketHost,
    configureSession,
    nickname,
    profileUrl,
    accessToken
  } = _ref3;
  return new Promise((resolve, reject) => {
    var _logger$info;
    logger === null || logger === void 0 ? void 0 : (_logger$info = logger.info) === null || _logger$info === void 0 ? void 0 : _logger$info.call(logger, 'SendbirdProvider | useConnect/setupConnection/init', {
      userId,
      appId
    });
    sdkDispatcher({
      type: SET_SDK_LOADING,
      payload: true
    });
    if (userId && appId) {
      var _logger$info3, _logger$info8;
      const newSdk = setUpParams({
        appId,
        customApiHost,
        customWebSocketHost
      });
      if (configureSession && typeof configureSession === 'function') {
        var _logger$info2;
        const sessionHandler = configureSession(newSdk);
        logger === null || logger === void 0 ? void 0 : (_logger$info2 = logger.info) === null || _logger$info2 === void 0 ? void 0 : _logger$info2.call(logger, 'SendbirdProvider | useConnect/setupConnection/configureSession', sessionHandler);
        newSdk.setSessionHandler(sessionHandler);
      }
      logger === null || logger === void 0 ? void 0 : (_logger$info3 = logger.info) === null || _logger$info3 === void 0 ? void 0 : _logger$info3.call(logger, 'SendbirdProvider | useConnect/setupConnection/setVersion', {
        version: APP_VERSION_STRING
      });
      newSdk.addExtension('sb_uikit', APP_VERSION_STRING);
      const connectCbSucess = async user => {
        var _logger$info4;
        logger === null || logger === void 0 ? void 0 : (_logger$info4 = logger.info) === null || _logger$info4 === void 0 ? void 0 : _logger$info4.call(logger, 'SendbirdProvider | useConnect/setupConnection/connectCbSucess', user);
        sdkDispatcher({
          type: INIT_SDK,
          payload: newSdk
        });
        userDispatcher({
          type: INIT_USER,
          payload: user
        });
        initDashboardConfigs(newSdk).then(config => {
          var _logger$info5;
          logger === null || logger === void 0 ? void 0 : (_logger$info5 = logger.info) === null || _logger$info5 === void 0 ? void 0 : _logger$info5.call(logger, 'SendbirdProvider | useConnect/setupConnection/getUIKitConfiguration success', {
            config
          });
        }).catch(error => {
          var _logger$error;
          logger === null || logger === void 0 ? void 0 : (_logger$error = logger.error) === null || _logger$error === void 0 ? void 0 : _logger$error.call(logger, 'SendbirdProvider | useConnect/setupConnection/getUIKitConfiguration failed', {
            error
          });
        });

        // use nickname/profileUrl if provided
        // or set userID as nickname
        if ((nickname !== user.nickname || profileUrl !== user.profileUrl) && !(isTextuallyNull(nickname) && isTextuallyNull(profileUrl))) {
          var _logger$info6;
          logger === null || logger === void 0 ? void 0 : (_logger$info6 = logger.info) === null || _logger$info6 === void 0 ? void 0 : _logger$info6.call(logger, 'SendbirdProvider | useConnect/setupConnection/updateCurrentUserInfo', {
            nickname,
            profileUrl
          });
          newSdk.updateCurrentUserInfo({
            nickname: nickname || user.nickname,
            profileUrl: profileUrl || user.profileUrl
          }).then(namedUser => {
            var _logger$info7;
            logger === null || logger === void 0 ? void 0 : (_logger$info7 = logger.info) === null || _logger$info7 === void 0 ? void 0 : _logger$info7.call(logger, 'SendbirdProvider | useConnect/setupConnection/updateCurrentUserInfo success', {
              nickname,
              profileUrl
            });
            userDispatcher({
              type: UPDATE_USER_INFO,
              payload: namedUser
            });
          }).finally(() => {
            resolve();
          });
        } else {
          resolve();
        }
      };
      const connectCbError = e => {
        var _logger$error2;
        const errorMessage = getConnectSbError(e);
        logger === null || logger === void 0 ? void 0 : (_logger$error2 = logger.error) === null || _logger$error2 === void 0 ? void 0 : _logger$error2.call(logger, errorMessage, {
          e,
          appId,
          userId
        });
        sdkDispatcher({
          type: RESET_SDK
        });
        userDispatcher({
          type: RESET_USER
        });
        sdkDispatcher({
          type: SDK_ERROR
        });
        // exit promise with error
        reject(errorMessage);
      };
      logger === null || logger === void 0 ? void 0 : (_logger$info8 = logger.info) === null || _logger$info8 === void 0 ? void 0 : _logger$info8.call(logger, `SendbirdProvider | useConnect/setupConnection/connect connecting using ${accessToken !== null && accessToken !== void 0 ? accessToken : userId}`);
      newSdk.connect(userId, accessToken).then(res => connectCbSucess(res)).catch(err => connectCbError(err));
    } else {
      var _logger$error3;
      const errorMessage = getMissingParamError({
        userId,
        appId
      });
      sdkDispatcher({
        type: SDK_ERROR
      });
      logger === null || logger === void 0 ? void 0 : (_logger$error3 = logger.error) === null || _logger$error3 === void 0 ? void 0 : _logger$error3.call(logger, errorMessage);
      // exit promise with error
      reject(errorMessage);
    }
  });
}

async function connect(_ref) {
  let {
    logger,
    sdkDispatcher,
    userDispatcher,
    initDashboardConfigs,
    userId,
    appId,
    customApiHost,
    customWebSocketHost,
    configureSession,
    nickname,
    profileUrl,
    accessToken,
    sdk
  } = _ref;
  await disconnectSdk({
    logger,
    sdkDispatcher,
    userDispatcher,
    sdk
  });
  await setUpConnection({
    logger,
    sdkDispatcher,
    userDispatcher,
    initDashboardConfigs,
    userId,
    appId,
    customApiHost,
    customWebSocketHost,
    configureSession,
    nickname,
    profileUrl,
    accessToken
  });
}

function useConnect(triggerTypes, staticTypes) {
  var _logger$info;
  const {
    userId,
    appId,
    accessToken
  } = triggerTypes;
  const {
    logger,
    nickname,
    profileUrl,
    configureSession,
    customApiHost,
    customWebSocketHost,
    sdk,
    sdkDispatcher,
    userDispatcher,
    initDashboardConfigs
  } = staticTypes;
  logger === null || logger === void 0 ? void 0 : (_logger$info = logger.info) === null || _logger$info === void 0 ? void 0 : _logger$info.call(logger, 'SendbirdProvider | useConnect', _objectSpread2(_objectSpread2({}, triggerTypes), staticTypes));
  useEffect(() => {
    var _logger$info2;
    logger === null || logger === void 0 ? void 0 : (_logger$info2 = logger.info) === null || _logger$info2 === void 0 ? void 0 : _logger$info2.call(logger, 'SendbirdProvider | useConnect/useEffect', {
      userId,
      appId,
      accessToken
    });
    try {
      connect({
        userId,
        appId,
        accessToken,
        logger,
        nickname,
        profileUrl,
        configureSession,
        customApiHost,
        customWebSocketHost,
        sdk,
        sdkDispatcher,
        userDispatcher,
        initDashboardConfigs
      });
    } catch (error) {
      var _logger$error;
      logger === null || logger === void 0 ? void 0 : (_logger$error = logger.error) === null || _logger$error === void 0 ? void 0 : _logger$error.call(logger, 'SendbirdProvider | useConnect/useEffect', error);
    }
  }, [userId, appId, accessToken]);
  const reconnect = useCallback(() => {
    var _logger$info3;
    logger === null || logger === void 0 ? void 0 : (_logger$info3 = logger.info) === null || _logger$info3 === void 0 ? void 0 : _logger$info3.call(logger, 'SendbirdProvider | useConnect/reconnect/useCallback', {
      sdk
    });
    try {
      connect({
        userId,
        appId,
        accessToken,
        logger,
        nickname,
        profileUrl,
        configureSession,
        customApiHost,
        customWebSocketHost,
        sdk,
        sdkDispatcher,
        userDispatcher,
        initDashboardConfigs
      });
    } catch (error) {
      var _logger$error2;
      logger === null || logger === void 0 ? void 0 : (_logger$error2 = logger.error) === null || _logger$error2 === void 0 ? void 0 : _logger$error2.call(logger, 'SendbirdProvider | useConnect/reconnect/useCallback', error);
    }
  }, [sdk]);
  return reconnect;
}

// Logger, pretty much explains it
// in SendbirdProvider

// const [logger, setLogger] = useState(LoggerFactory(logLevel));
const LOG_LEVELS = {
  DEBUG: 'debug',
  WARNING: 'warning',
  ERROR: 'error',
  INFO: 'info',
  ALL: 'all'
};
const colorLog = level => {
  switch (level) {
    case LOG_LEVELS.WARNING:
      return 'color: Orange';
    case LOG_LEVELS.ERROR:
      return 'color: Red';
    default:
      return 'color: Gray';
  }
};
const printLog = _ref => {
  let {
    level,
    title,
    description = ''
  } = _ref;
  // eslint-disable-next-line no-console
  console.log(`%c SendbirdUIKit | ${level} | ${new Date().toISOString()} | ${title} ${description && '|'}`, colorLog(level), description);
};
const noop = () => {/* noop */};
const getDefaultLogger = () => ({
  info: noop,
  error: noop,
  warning: noop
});
const LoggerFactory = (lvl, customInterface) => {
  const logInterface = customInterface || printLog;
  const lvlArray = Array.isArray(lvl) ? lvl : [lvl];
  const applyLog = lgLvl => (title, description) => logInterface({
    level: lgLvl,
    title,
    description
  });
  const logger = lvlArray.reduce((accumulator, currentLvl) => {
    if (currentLvl === LOG_LEVELS.DEBUG || currentLvl === LOG_LEVELS.ALL) {
      return _objectSpread2(_objectSpread2({}, accumulator), {}, {
        info: applyLog(LOG_LEVELS.INFO),
        error: applyLog(LOG_LEVELS.ERROR),
        warning: applyLog(LOG_LEVELS.WARNING)
      });
    }
    if (currentLvl === LOG_LEVELS.INFO) {
      return _objectSpread2(_objectSpread2({}, accumulator), {}, {
        info: applyLog(LOG_LEVELS.INFO)
      });
    }
    if (currentLvl === LOG_LEVELS.ERROR) {
      return _objectSpread2(_objectSpread2({}, accumulator), {}, {
        error: applyLog(LOG_LEVELS.ERROR)
      });
    }
    if (currentLvl === LOG_LEVELS.WARNING) {
      return _objectSpread2(_objectSpread2({}, accumulator), {}, {
        warning: applyLog(LOG_LEVELS.WARNING)
      });
    }
    return _objectSpread2({}, accumulator);
  }, getDefaultLogger());
  return logger;
};

// TODO: Make this to hook, useLogger

// https://davidwalsh.name/pubsub-javascript
// we use pubsub to sync events between multiple components(example - ChannelList, Channel)
// for example, if customer sends a message from their custom component
// without pubsub,we would not be able to listen to it
// in our ChannelList or Conversation

const pubSubFactory = () => {
  const topics = {};
  const hOP = topics.hasOwnProperty;
  return {
    __getTopics: () => topics,
    subscribe: (topic, listener) => {
      // Create the topic's object if not yet created
      if (!hOP.call(topics, topic)) {
        topics[topic] = [];
      }

      // Add the listener to queue
      const index = topics[topic].push(listener) - 1;

      // Provide handle back for removal of topic
      return {
        remove: () => {
          delete topics[topic][index];
        }
      };
    },
    publish: (topic, info) => {
      // If the topic doesn't exist, or there's no listeners in queue, just leave
      if (!hOP.call(topics, topic)) {
        return;
      }

      // Cycle through topics queue, fire!
      topics[topic].forEach(item => {
        item(info !== undefined ? info : {});
      });
    }
  };
};

/* eslint-disable default-param-last */
function useAppendDomNode() {
  let ids = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  let rootSelector = arguments.length > 1 ? arguments[1] : undefined;
  useEffect(() => {
    const root = document.querySelector(rootSelector);
    ids.forEach(id => {
      const elem = document.createElement('div');
      elem.setAttribute('id', id);
      root.appendChild(elem);
    });
    return () => {
      ids.forEach(id => {
        const target = document.getElementById(id);
        if (target) {
          root.removeChild(target);
        }
      });
    };
  }, []);
}

function snakeToCamel(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  if (Array.isArray(obj)) {
    return obj.map(item => snakeToCamel(item));
  }
  const result = {};
  Object.keys(obj).forEach(key => {
    const camelKey = key.replace(/_\w/g, m => m[1].toUpperCase());
    result[camelKey] = snakeToCamel(obj[key]);
  });
  return result;
}

// @link https://gist.github.com/navix/6c25c15e0a2d3cd0e5bce999e0086fc9
/* eslint-disable @typescript-eslint/ban-types */

function isSameType(a, b) {
  // we do this cause typeof can't differenciate object/ array/ null
  return Object.prototype.toString.call(a) === Object.prototype.toString.call(b);
}

/**
 * @param localConfigs Set directly in code level. It has higher priority than remote ones
 * @param remoteConfigs Set by Feature Config setting in Dashboard
 * @returns
 */
function getConfigsByPriority(localConfigs, remoteConfigs) {
  const prioritizedConfigs = _objectSpread2({}, remoteConfigs); // copy remoteConfigs to prevent mutation

  Object.keys(localConfigs).forEach(key => {
    if (prioritizedConfigs.hasOwnProperty(key) && isSameType(localConfigs[key], prioritizedConfigs[key])) {
      prioritizedConfigs[key] = typeof localConfigs[key] === 'object'
      // Recursively call getConfigsByPriority only when the value of the key is Object
      ? getConfigsByPriority(localConfigs[key], prioritizedConfigs[key]) : localConfigs[key];
    }
  });
  return prioritizedConfigs;
}

// @link: https://docs.google.com/spreadsheets/d/1-AozBMHRYOXS74vZ-7x2ptQcBL6nnM-orJWRvUgmkd4/edit#gid=0
const initialConfig = {
  common: {
    enableUsingDefaultUserProfile: false
  },
  groupChannel: {
    channel: {
      enableMention: false,
      enableOgtag: true,
      enableReactions: true,
      enableTypingIndicator: true,
      enableVoiceMessage: false,
      input: {
        camera: {
          enablePhoto: true,
          enableVideo: true
        },
        enableDocument: true,
        gallery: {
          enablePhoto: true,
          enableVideo: true
        }
      },
      replyType: 'quote_reply',
      threadReplySelectType: 'thread'
    },
    channelList: {
      enableMessageReceiptStatus: false,
      enableTypingIndicator: false
    },
    setting: {
      enableMessageSearch: false
    }
  },
  openChannel: {
    channel: {
      enableOgtag: true,
      input: {
        camera: {
          enablePhoto: true,
          enableVideo: true
        },
        enableDocument: true,
        gallery: {
          enablePhoto: true,
          enableVideo: true
        }
      }
    }
  }
};

class UIKitConfigStorageManager {
  constructor(storage) {
    _defineProperty(this, "key", void 0);
    _defineProperty(this, "storage", void 0);
    this.storage = storage;
  }
  init(appId) {
    this.key = `sbu@${appId}.uikitConfiguration`;
    return this.get();
  }
  async update(payload) {
    const storedConfig = await this.get();
    const mergedConfig = {
      lastUpdatedAt: payload.lastUpdatedAt,
      uikitConfigurations: getConfigsByPriority(payload === null || payload === void 0 ? void 0 : payload.uikitConfigurations, storedConfig === null || storedConfig === void 0 ? void 0 : storedConfig.uikitConfigurations)
    };
    await this.storage.setItem(this.key, JSON.stringify(mergedConfig));
    return mergedConfig;
  }
  async get() {
    const initialPayload = {
      lastUpdatedAt: 0,
      uikitConfigurations: initialConfig
    };
    try {
      const storedConfig = await this.storage.getItem(this.key);
      if (storedConfig) {
        // TODO: Validation
        return JSON.parse(storedConfig);
      } else {
        return initialPayload;
      }
    } catch (_unused) {
      return initialPayload;
    }
  }
}

const UIKitConfigContext = /*#__PURE__*/createContext({
  initDashboardConfigs: () => Promise.resolve(),
  configs: initialConfig
});
const UIKitConfigProvider = _ref => {
  let {
    storage,
    children,
    localConfigs
  } = _ref;
  // Set by Feature Config setting in Dashboard
  const [remoteConfigs, setRemoteConfigs] = useState(initialConfig);
  const initDashboardConfigs = useCallback(async sdk => {
    try {
      if (storage == null) {
        const payload = await sdk.getUIKitConfiguration();
        setRemoteConfigs(snakeToCamel(payload.json.uikit_configurations));
        return;
      }

      // Compare the sdk uikitConfig's lastUpdatedAt <-> stored one
      const manager = new UIKitConfigStorageManager(storage);
      const storedConfigs = await manager.init(sdk.appId);
      if (sdk.appInfo.uikitConfigInfo.lastUpdatedAt === storedConfigs.lastUpdatedAt) {
        setRemoteConfigs(storedConfigs.uikitConfigurations);
      } else {
        const payload = await sdk.getUIKitConfiguration();
        const updatedPayloed = await manager.update(snakeToCamel(payload.json));
        setRemoteConfigs(updatedPayloed.uikitConfigurations);
      }
    } catch (error) {
      //
    }
  }, []);
  const configs = getConfigsByPriority(localConfigs, remoteConfigs);
  return /*#__PURE__*/React__default.createElement(UIKitConfigContext.Provider, {
    value: {
      initDashboardConfigs,
      configs
    }
  }, children);
};
const useUIKitConfig = () => useContext(UIKitConfigContext);

const VoiceMessageProvider = _ref => {
  let {
    children,
    isVoiceMessageEnabled = true
  } = _ref;
  if (!isVoiceMessageEnabled) {
    return /*#__PURE__*/React__default.createElement(VoicePlayerProvider, null, children);
  }
  return /*#__PURE__*/React__default.createElement(VoiceRecorderProvider, null, /*#__PURE__*/React__default.createElement(VoicePlayerProvider, null, children));
};

const TIMEOUT = 2000;

/*
  * This is a factory function that returns a scheduler.
  * The scheduler is a queue that calls the callback function on intervals.
  * If interval is empty, the callback function is called immediately.
  * If interval is not empty, the callback function is called after the interval.
*/
function schedulerFactory(_ref) {
  let {
    logger,
    timeout,
    cb
  } = _ref;
  let queue = [];
  let interval = null;
  const push = channel => {
    const channelPresent = queue.find(c => c.url === channel.url);
    if (!channelPresent) {
      queue.push(channel);
    } else {
      logger.info('Channel: Mark as read already in queue', {
        channel
      });
    }
    // start the interval if it's not already running
    if (interval) {
      return;
    }
    const item = queue.shift();
    if (item) {
      cb(item);
    }
    interval = setInterval(() => {
      if (queue.length === 0 && interval) {
        clearInterval(interval);
        interval = null;
        return;
      }
      const item = queue.shift();
      if (item) {
        cb(item);
      }
    }, timeout || TIMEOUT);
  };
  const clear = () => {
    queue = [];
    if (interval) {
      clearInterval(interval);
      interval = null;
    }
  };
  return {
    push,
    clear,
    getQueue: () => queue
  };
}

// this hook accepts a callback to run component is unmounted
function useUnmount(callback) {
  useLayoutEffect(() => {
    return () => {
      callback();
    };
  }, []);
}

function useMarkAsReadScheduler(_ref, _ref2) {
  let {
    isConnected
  } = _ref;
  let {
    logger
  } = _ref2;
  const markAsReadScheduler = useMemo(() => schedulerFactory({
    logger,
    cb: channel => {
      try {
        channel.markAsRead();
      } catch (error) {
        logger.warning('Channel: Mark as delivered failed', {
          channel,
          error
        });
      }
    }
  }), []);
  useEffect(() => {
    // for simplicity, we clear the queue when the connection is lost
    if (!isConnected) {
      markAsReadScheduler.clear();
    }
  }, [isConnected]);
  useUnmount(() => {
    markAsReadScheduler.clear();
  });
  return markAsReadScheduler;
}

function useMarkAsDeliveredScheduler(_ref, _ref2) {
  let {
    isConnected
  } = _ref;
  let {
    logger
  } = _ref2;
  const markAsDeliveredScheduler = useMemo(() => schedulerFactory({
    logger,
    cb: channel => {
      try {
        channel.markAsDelivered();
      } catch (error) {
        logger.warning('Channel: Mark as delivered failed', {
          channel,
          error
        });
      }
    }
  }), []);
  useEffect(() => {
    // for simplicity, we clear the queue when the connection is lost
    if (!isConnected) {
      markAsDeliveredScheduler.clear();
    }
  }, [isConnected]);
  useUnmount(() => {
    markAsDeliveredScheduler.clear();
  });
  return markAsDeliveredScheduler;
}

function Sendbird(props) {
  const {
    replyType,
    isMentionEnabled,
    isReactionEnabled,
    disableUserProfile,
    isVoiceMessageEnabled,
    isTypingIndicatorEnabledOnChannelList,
    isMessageReceiptStatusEnabledOnChannelList
  } = props;
  return /*#__PURE__*/React__default.createElement(UIKitConfigProvider, {
    localConfigs: {
      common: {
        enableUsingDefaultUserProfile: !disableUserProfile
      },
      groupChannel: {
        channel: {
          enableReactions: isReactionEnabled,
          enableMention: isMentionEnabled,
          enableVoiceMessage: isVoiceMessageEnabled,
          /**
           * Since dashbord UIKit Configuration's replyType is consisted of all lowercase letters,
           * we convert it from here.
           * i.e. 'THREAD' -> 'thread'
           */
          replyType: replyType.toLowerCase()
        },
        channelList: {
          enableTypingIndicator: isTypingIndicatorEnabledOnChannelList,
          enableMessageReceiptStatus: isMessageReceiptStatusEnabledOnChannelList
        }
      }
    }
  }, /*#__PURE__*/React__default.createElement(SendbirdSDK, props));
}
const SendbirdSDK = _ref => {
  let {
    appId,
    userId,
    children,
    accessToken = '',
    customApiHost = '',
    customWebSocketHost = '',
    configureSession = null,
    theme = 'light',
    config = {},
    nickname = '',
    colorSet = null,
    stringSet = null,
    dateLocale = null,
    profileUrl = '',
    voiceRecord = {
      maxRecordingTime: VOICE_RECORDER_DEFAULT_MAX,
      minRecordingTime: VOICE_RECORDER_DEFAULT_MIN
    },
    userListQuery = null,
    imageCompression = {},
    allowProfileEdit = false,
    disableMarkAsDelivered = false,
    renderUserProfile = null,
    onUserProfileMessage = null
  } = _ref;
  const breakpoint = false;
  const {
    logLevel = '',
    userMention = {},
    isREMUnitEnabled = false
  } = config;
  const [logger, setLogger] = useState(LoggerFactory(logLevel));
  const [pubSub] = useState(pubSubFactory());
  const [sdkStore, sdkDispatcher] = useReducer(reducer$1, initialState$1);
  const [userStore, userDispatcher] = useReducer(reducer, initialState);
  const {
    configs,
    initDashboardConfigs
  } = useUIKitConfig();
  useTheme(colorSet);
  const reconnect = useConnect({
    appId,
    userId,
    accessToken
  }, {
    logger,
    nickname,
    profileUrl,
    configureSession,
    customApiHost,
    customWebSocketHost,
    sdk: sdkStore === null || sdkStore === void 0 ? void 0 : sdkStore.sdk,
    sdkDispatcher,
    userDispatcher,
    initDashboardConfigs
  });

  // to create a pubsub to communicate between parent and child
  useEffect(() => {
    setLogger(LoggerFactory(logLevel));
  }, [logLevel]);
  useAppendDomNode(['sendbird-modal-root', 'sendbird-dropdown-portal', 'sendbird-emoji-list-portal'], 'body');

  // should move to reducer
  const [currenttheme, setCurrenttheme] = useState(theme);
  useEffect(() => {
    setCurrenttheme(theme);
  }, [theme]);
  useEffect(() => {
    const body = document.querySelector('body');
    body.classList.remove('sendbird-experimental__rem__units');
    if (isREMUnitEnabled) {
      body.classList.add('sendbird-experimental__rem__units');
    }
  }, [isREMUnitEnabled]);
  // add-remove theme from body
  useEffect(() => {
    logger.info('Setup theme', `Theme: ${currenttheme}`);
    try {
      const body = document.querySelector('body');
      body.classList.remove('sendbird-theme--light');
      body.classList.remove('sendbird-theme--dark');
      body.classList.add(`sendbird-theme--${currenttheme || 'light'}`);
      logger.info('Finish setup theme');
      // eslint-disable-next-line no-empty
    } catch (e) {
      logger.warning('Setup theme failed', `${e}`);
    }
    return () => {
      try {
        const body = document.querySelector('body');
        body.classList.remove('sendbird-theme--light');
        body.classList.remove('sendbird-theme--dark');
        // eslint-disable-next-line no-empty
      } catch (_unused) {}
    };
  }, [currenttheme]);
  const isOnline = useConnectionStatus(sdkStore.sdk, logger);
  const markAsReadScheduler = useMarkAsReadScheduler({
    isConnected: isOnline
  }, {
    logger
  });
  const markAsDeliveredScheduler = useMarkAsDeliveredScheduler({
    isConnected: isOnline
  }, {
    logger
  });
  const localeStringSet = React__default.useMemo(() => {
    if (!stringSet) {
      return getStringSet('en');
    }
    return _objectSpread2(_objectSpread2({}, getStringSet('en')), stringSet);
  }, [stringSet]);
  return /*#__PURE__*/React__default.createElement(SendbirdSdkContext.Provider, {
    value: {
      stores: {
        sdkStore,
        userStore
      },
      dispatchers: {
        sdkDispatcher,
        userDispatcher,
        reconnect
      },
      config: {
        disableMarkAsDelivered,
        renderUserProfile,
        onUserProfileMessage,
        allowProfileEdit,
        isOnline,
        userId,
        appId,
        accessToken,
        theme: currenttheme,
        setCurrenttheme,
        userListQuery,
        logger,
        pubSub,
        imageCompression: _objectSpread2({
          compressionRate: 0.7
        }, imageCompression),
        voiceRecord,
        userMention: {
          maxMentionCount: (userMention === null || userMention === void 0 ? void 0 : userMention.maxMentionCount) || 10,
          maxSuggestionCount: (userMention === null || userMention === void 0 ? void 0 : userMention.maxSuggestionCount) || 15
        },
        markAsReadScheduler,
        markAsDeliveredScheduler,
        // From UIKitConfigProvider.localConfigs
        disableUserProfile: !configs.common.enableUsingDefaultUserProfile,
        isReactionEnabled: configs.groupChannel.channel.enableReactions,
        isMentionEnabled: configs.groupChannel.channel.enableMention,
        isVoiceMessageEnabled: configs.groupChannel.channel.enableVoiceMessage,
        replyType:
        /**
         * Since UIKitConfigContext's replyType is consisted of all lowercase letters,
         * we need to convert it into all uppercase ones like
         *  - 'thread' -> 'THREAD'
         *  - 'quote_reply' -> 'QUOTE_REPLY'
         */
        configs.groupChannel.channel.replyType.toUpperCase(),
        isTypingIndicatorEnabledOnChannelList: configs.groupChannel.channelList.enableTypingIndicator,
        isMessageReceiptStatusEnabledOnChannelList: configs.groupChannel.channelList.enableMessageReceiptStatus
        // TODO(Ahyoung): add more configs from UIKitConfigProvider.remoteConfigs
      }
    }
  }, /*#__PURE__*/React__default.createElement(MediaQueryProvider, {
    logger: logger,
    breakpoint: breakpoint
  }, /*#__PURE__*/React__default.createElement(LocalizationProvider, {
    stringSet: localeStringSet,
    dateLocale: dateLocale
  }, /*#__PURE__*/React__default.createElement(VoiceMessageProvider, {
    isVoiceMessageEnabled: configs.groupChannel.channel.enableVoiceMessage
  }, children))));
};

export { Sendbird as default };
//# sourceMappingURL=SendbirdProvider.js.map
