'use strict';

var electron = require('electron');
var redux = require('redux');
var detectBrowsers = require('detect-browsers');
var fs = require('fs');
var path = require('path');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var fs__default = /*#__PURE__*/_interopDefault(fs);
var path__default = /*#__PURE__*/_interopDefault(path);

const handle = (channel, handler) => {
  const listener = async (_, id, ...args) => {
    try {
      const resolved = await handler(...args);
      electron.ipcRenderer.send(`${channel}@${id}`, {
        resolved
      });
    } catch (error) {
      error instanceof Error && electron.ipcRenderer.send(`${channel}@${id}`, {
        rejected: {
          name: error.name,
          message: error.message,
          stack: error.stack
        }
      });
    }
  };
  electron.ipcRenderer.on(channel, listener);
  return () => {
    electron.ipcRenderer.removeListener(channel, listener);
  };
};
const invoke = (channel, ...args) => electron.ipcRenderer.invoke(channel, ...args);

const jitsiDomain = window.location.origin;
const desktopCapturer = {
  getSources: opts => electron.ipcRenderer.invoke('jitsi-desktop-capturer-get-sources', [opts, jitsiDomain])
};
const JitsiMeetElectron = {
  async obtainDesktopStreams(callback, errorCallback, options) {
    try {
      const sources = (await desktopCapturer.getSources(options)).map(source => ({
        id: source.id,
        name: source.name,
        display_id: source.display_id,
        thumbnail: {
          toDataURL: () => source.thumbnail.toDataURL()
        },
        appIcon: {
          toDataURL: () => source.appIcon.toDataURL()
        }
      }));
      callback(sources);
    } catch (error) {
      error instanceof Error && errorCallback(error);
      console.log(error);
    }
  }
};

let getAbsoluteUrl;
let serverUrl;
const setServerUrl = _serverUrl => {
  serverUrl = _serverUrl;
};
const getServerUrl = () => serverUrl;
const setUrlResolver = _getAbsoluteUrl => {
  getAbsoluteUrl = _getAbsoluteUrl;
};

const isFSA = action => typeof action === 'object' && action !== null && !Array.isArray(action) && 'type' in action && typeof action.type === 'string';
const hasMeta = action => 'meta' in action && typeof action.meta === 'object' && action.meta !== null;
const isResponse = action => hasMeta(action) && action.meta.response === true;
const isLocallyScoped = action => hasMeta(action) && action.meta.scope === 'local';
const isErrored = action => 'meta' in action && action.error === true && action.payload instanceof Error;
const hasPayload = action => 'payload' in action;
const isResponseTo = (id, ...types) => action => isResponse(action) && types.includes(action.type) && action.meta.id === id;

const getInitialState = () => invoke('redux/get-initial-state');
const forwardToMain = api => {
  handle('redux/action-dispatched', async action => {
    api.dispatch(action);
  });
  return next => action => {
    if (!isFSA(action) || isLocallyScoped(action)) {
      return next(action);
    }
    invoke('redux/action-dispatched', action);
    return action;
  };
};

const APP_PATH_SET = 'app/path-set';
const APP_VERSION_SET = 'app/version-set';
const APP_SETTINGS_LOADED = 'app/settings-loaded';
const APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET = 'app/allowed-ntlm-credentials-domains-set';
const APP_MAIN_WINDOW_TITLE_SET = 'app/main-window-title-set';
const APP_MACHINE_THEME_SET = 'app/machine-theme-set';
const APP_SCREEN_CAPTURE_FALLBACK_FORCED_SET = 'app/screen-capture-fallback-forced-set';

const allowedNTLMCredentialsDomains = (state = null, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          allowedNTLMCredentialsDomains = state
        } = action.payload;
        return allowedNTLMCredentialsDomains;
      }
    case APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET:
      {
        if (action.payload === null) return null;
        return action.payload;
      }
    default:
      return state;
  }
};

const appPath = (state = null, action) => {
  switch (action.type) {
    case APP_PATH_SET:
      return action.payload;
    default:
      return state;
  }
};

const appVersion = (state = null, action) => {
  switch (action.type) {
    case APP_VERSION_SET:
      return action.payload;
    default:
      return state;
  }
};

const machineTheme = (state = 'light', action) => {
  switch (action.type) {
    case APP_MACHINE_THEME_SET:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const mainWindowTitle = (state = null, action) => {
  switch (action.type) {
    case APP_MAIN_WINDOW_TITLE_SET:
      return action.payload;
    default:
      return state;
  }
};

const screenCaptureFallbackForced = (state = false, action) => {
  switch (action.type) {
    case APP_SCREEN_CAPTURE_FALLBACK_FORCED_SET:
      return action.payload;
    default:
      return state;
  }
};

const DOWNLOAD_CREATED = 'downloads/created';
const DOWNLOAD_REMOVED = 'downloads/removed';
const DOWNLOADS_CLEARED = 'downloads/cleared';
const DOWNLOAD_UPDATED = 'downloads/updated';

const DownloadStatus = {
  ALL: 'All',
  PAUSED: 'Paused',
  CANCELLED: 'Cancelled'
};

const downloads = (state = {}, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        var _action$payload$downl;
        const initDownloads = (_action$payload$downl = action.payload.downloads) !== null && _action$payload$downl !== undefined ? _action$payload$downl : {};
        Object.values(initDownloads).forEach(value => {
          if (value.state === 'progressing' || value.state === 'paused') {
            value.state = 'cancelled';
            value.status = DownloadStatus.CANCELLED;
          }
        });
        return initDownloads !== null && initDownloads !== undefined ? initDownloads : {};
      }
    case DOWNLOAD_CREATED:
      {
        const download = action.payload;
        return {
          ...state,
          [download.itemId]: download
        };
      }
    case DOWNLOAD_UPDATED:
      {
        const existingDownload = state[action.payload.itemId];
        if (!existingDownload) {
          return state; // Don't update if download doesn't exist
        }
        const newState = {
          ...state
        };
        newState[action.payload.itemId] = {
          ...existingDownload,
          ...action.payload
        };
        return newState;
      }
    case DOWNLOAD_REMOVED:
      {
        const newState = {
          ...state
        };
        delete newState[action.payload];
        return newState;
      }
    case DOWNLOADS_CLEARED:
      return {};
    default:
      return state;
  }
};

const JITSI_SERVER_CAPTURE_SCREEN_PERMISSION_UPDATED = 'jitsi-server-capture-screen-permission-updated';
const JITSI_SERVER_CAPTURE_SCREEN_PERMISSIONS_CLEARED = 'jitsi-server-capture-screen-permissions-cleared';

const allowedJitsiServers = (state = {}, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          allowedJitsiServers = {}
        } = action.payload;
        state = allowedJitsiServers;
        return state;
      }
    case JITSI_SERVER_CAPTURE_SCREEN_PERMISSION_UPDATED:
      {
        state = {
          ...state,
          [action.payload.jitsiServer]: action.payload.allowed
        };
        return state;
      }
    case JITSI_SERVER_CAPTURE_SCREEN_PERMISSIONS_CLEARED:
      {
        state = {};
        return state;
      }
    default:
      return state;
  }
};

const CERTIFICATES_CLEARED = 'certificates/cleared';
const CERTIFICATES_LOADED = 'certificates/loaded';
const CERTIFICATES_CLIENT_CERTIFICATE_REQUESTED = 'certificates/client-certificate-requested';
const TRUSTED_CERTIFICATES_UPDATED = 'trusted-certificates/updated';
const NOT_TRUSTED_CERTIFICATES_UPDATED = 'not-trusted-certificates/updated';
const SELECT_CLIENT_CERTIFICATE_DIALOG_CERTIFICATE_SELECTED = 'select-client-certificate-dialog/certificate-selected';
const SELECT_CLIENT_CERTIFICATE_DIALOG_DISMISSED = 'select-client-certificate-dialog/dismissed';
const EXTERNAL_PROTOCOL_PERMISSION_UPDATED = 'navigation/external-protocol-permission-updated';

const clientCertificates = (state = [], action) => {
  switch (action.type) {
    case CERTIFICATES_CLIENT_CERTIFICATE_REQUESTED:
      return action.payload;
    case SELECT_CLIENT_CERTIFICATE_DIALOG_CERTIFICATE_SELECTED:
    case SELECT_CLIENT_CERTIFICATE_DIALOG_DISMISSED:
      return [];
    default:
      return state;
  }
};
const trustedCertificates = (state = {}, action) => {
  switch (action.type) {
    case CERTIFICATES_LOADED:
    case TRUSTED_CERTIFICATES_UPDATED:
      return action.payload;
    case CERTIFICATES_CLEARED:
      return {};
    case APP_SETTINGS_LOADED:
      {
        const {
          trustedCertificates = state
        } = action.payload;
        return trustedCertificates;
      }
    default:
      return state;
  }
};
const notTrustedCertificates = (state = {}, action) => {
  switch (action.type) {
    case NOT_TRUSTED_CERTIFICATES_UPDATED:
      return action.payload;
    case CERTIFICATES_CLEARED:
      return {};
    case APP_SETTINGS_LOADED:
      {
        const {
          notTrustedCertificates = state
        } = action.payload;
        return notTrustedCertificates;
      }
    default:
      return state;
  }
};
const externalProtocols = (state = {}, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          externalProtocols = {}
        } = action.payload;
        state = externalProtocols;
        return state;
      }
    case EXTERNAL_PROTOCOL_PERMISSION_UPDATED:
      {
        state = {
          ...state,
          [action.payload.protocol]: action.payload.allowed
        };
        return state;
      }
    default:
      return state;
  }
};

/**
 * Controls whether to bypass SSL certificate validation for Outlook calendar connections.
 * This setting is intended for air-gapped environments where Exchange servers use
 * self-signed certificates or internal CA certificates that are not in the system trust store.
 *
 * Configurable via overridden-settings.json:
 * { "allowInsecureOutlookConnections": true }
 *
 * Defaults to false (secure connections with certificate validation).
 */
const allowInsecureOutlookConnections = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          allowInsecureOutlookConnections = state
        } = action.payload;
        return allowInsecureOutlookConnections;
      }
    default:
      return state;
  }
};

const ABOUT_DIALOG_DISMISSED = 'about-dialog/dismissed';
const ABOUT_DIALOG_TOGGLE_UPDATE_ON_START = 'about-dialog/toggle-update-on-start';
const ABOUT_DIALOG_UPDATE_CHANNEL_CHANGED = 'about-dialog/update-channel-changed';
const ADD_SERVER_VIEW_SERVER_ADDED = 'add-server/view-server-added';
const MENU_BAR_ABOUT_CLICKED = 'menu-bar/about-clicked';
const MENU_BAR_ADD_NEW_SERVER_CLICKED = 'menu-bar/add-new-server-clicked';
const MENU_BAR_SELECT_SERVER_CLICKED = 'menu-bar/select-server-clicked';
const MENU_BAR_TOGGLE_IS_MENU_BAR_ENABLED_CLICKED = 'menu-bar/toggle-is-menu-bar-enabled-clicked';
const MENU_BAR_TOGGLE_IS_SHOW_WINDOW_ON_UNREAD_CHANGED_ENABLED_CLICKED = 'menu-bar/toggle-is-show-window-on-unread-changed-enabled-clicked';
const MENU_BAR_TOGGLE_IS_SIDE_BAR_ENABLED_CLICKED = 'menu-bar/toggle-is-side-bar-enabled-clicked';
const MENU_BAR_TOGGLE_IS_TRAY_ICON_ENABLED_CLICKED = 'menu-bar/toggle-is-tray-icon-enabled-clicked';
const MENU_BAR_TOGGLE_IS_DEVELOPER_MODE_ENABLED_CLICKED = 'menu-bar/toggle-is-developer-mode-enabled-clicked';
const MENU_BAR_TOGGLE_IS_VIDEO_CALL_DEVTOOLS_AUTO_OPEN_ENABLED_CLICKED = 'menu-bar/toggle-is-video-call-devtools-auto-open-enabled-clicked';
const ROOT_WINDOW_ICON_CHANGED = 'root-window/icon-changed';
const ROOT_WINDOW_STATE_CHANGED = 'root-window/state-changed';
const VIDEO_CALL_WINDOW_STATE_CHANGED = 'video-call-window/state-changed';
const SIDE_BAR_ADD_NEW_SERVER_CLICKED = 'side-bar/add-new-server-clicked';
const SIDE_BAR_DOWNLOADS_BUTTON_CLICKED = 'side-bar/downloads-button-clicked';
const SIDE_BAR_SETTINGS_BUTTON_CLICKED = 'side-bar/settings-button-clicked';
const SIDE_BAR_REMOVE_SERVER_CLICKED = 'side-bar/remove-server-clicked';
const SIDE_BAR_SERVER_SELECTED = 'side-bar/server-selected';
const SIDE_BAR_SERVERS_SORTED = 'side-bar/servers-sorted';
const TOUCH_BAR_FORMAT_BUTTON_TOUCHED = 'touch-bar/format-button-touched';
const TOUCH_BAR_SELECT_SERVER_TOUCHED = 'touch-bar/select-server-touched';
const UPDATE_DIALOG_DISMISSED = 'update-dialog/dismissed';
const UPDATE_DIALOG_INSTALL_BUTTON_CLICKED = 'update-dialog/install-button-clicked';
const UPDATE_DIALOG_REMIND_UPDATE_LATER_CLICKED = 'update-dialog/remind-update-later-clicked';
const UPDATE_DIALOG_SKIP_UPDATE_CLICKED = 'update-dialog/skip-update-clicked';
const WEBVIEW_READY = 'webview/ready';
const WEBVIEW_ATTACHED = 'webview/attached';
const WEBVIEW_DID_FAIL_LOAD = 'webview/did-fail-load';
const WEBVIEW_DID_NAVIGATE = 'webview/did-navigate';
const WEBVIEW_DID_START_LOADING = 'webview/did-start-loading';
const WEBVIEW_FAVICON_CHANGED = 'webview/favicon-changed';
const WEBVIEW_FOCUS_REQUESTED = 'webview/focus-requested';
const WEBVIEW_MESSAGE_BOX_BLURRED = 'webview/message-box-blurred';
const WEBVIEW_MESSAGE_BOX_FOCUSED = 'webview/message-box-focused';
const WEBVIEW_SCREEN_SHARING_SOURCE_REQUESTED = 'webview/screen-sharing-source-requested';
const WEBVIEW_SCREEN_SHARING_SOURCE_RESPONDED = 'webview/screen-sharing-source-responded';
const WEBVIEW_SIDEBAR_STYLE_CHANGED = 'webview/sidebar-style-changed';
const WEBVIEW_SIDEBAR_CUSTOM_THEME_CHANGED = 'webview/sidebar-custom-theme-changed';
const WEBVIEW_GIT_COMMIT_HASH_CHANGED = 'webview/git-commit-hash-changed';
const WEBVIEW_GIT_COMMIT_HASH_CHECK = 'webview/git-commit-hash-check';
const WEBVIEW_TITLE_CHANGED = 'webview/title-changed';
const WEBVIEW_PAGE_TITLE_CHANGED = 'webview/page-title-changed';
const WEBVIEW_UNREAD_CHANGED = 'webview/unread-changed';
const WEBVIEW_USER_LOGGED_IN = 'webview/user-loggedin';
const WEBVIEW_ALLOWED_REDIRECTS_CHANGED = 'webview/allowed-redirects-changed';
const SETTINGS_SET_REPORT_OPT_IN_CHANGED = 'settings/set-bugsnag-opt-in-changed';
const SETTINGS_SET_FLASHFRAME_OPT_IN_CHANGED = 'settings/set-flashframe-opt-in-changed';
const SETTINGS_SET_HARDWARE_ACCELERATION_OPT_IN_CHANGED = 'settings/set-hardware-acceleration-opt-in-changed';
const SETTINGS_SET_INTERNALVIDEOCHATWINDOW_OPT_IN_CHANGED = 'settings/set-internalvideochatwindow-opt-in-changed';
const SETTINGS_SET_MINIMIZE_ON_CLOSE_OPT_IN_CHANGED = 'settings/set-minimize-on-close-opt-in-changed';
const SETTINGS_SET_IS_TRAY_ICON_ENABLED_CHANGED = 'settings/set-is-tray-icon-enabled-changed';
const SETTINGS_SET_IS_SIDE_BAR_ENABLED_CHANGED = 'settings/set-is-side-bar-enabled-changed';
const SETTINGS_SET_IS_MENU_BAR_ENABLED_CHANGED = 'settings/set-is-menu-bar-enabled-changed';
const SETTINGS_SET_IS_VIDEO_CALL_WINDOW_PERSISTENCE_ENABLED_CHANGED = 'settings/set-is-video-call-window-persistence-enabled-changed';
const SETTINGS_SET_IS_TRANSPARENT_WINDOW_ENABLED_CHANGED = 'settings/set-is-transparent-window-enabled-changed';
const SETTINGS_SET_IS_DEVELOPER_MODE_ENABLED_CHANGED = 'settings/set-is-developer-mode-enabled-changed';
const SETTINGS_SET_IS_VIDEO_CALL_DEVTOOLS_AUTO_OPEN_ENABLED_CHANGED = 'settings/set-is-video-call-devtools-auto-open-enabled-changed';
const SETTINGS_SET_IS_VIDEO_CALL_SCREEN_CAPTURE_FALLBACK_ENABLED_CHANGED = 'settings/set-is-video-call-screen-capture-fallback-enabled-changed';
const SETTINGS_SET_OUTLOOK_CALENDAR_SYNC_INTERVAL_CHANGED = 'settings/set-outlook-calendar-sync-interval-changed';
const SETTINGS_NTLM_CREDENTIALS_CHANGED = 'settings/ntlm-credentials-changed';
const SETTINGS_AVAILABLE_BROWSERS_UPDATED = 'settings/available-browsers-updated';
const SETTINGS_SELECTED_BROWSER_CHANGED = 'settings/selected-browser-changed';
const SETTINGS_USER_THEME_PREFERENCE_CHANGED = 'settings/user-theme-preference-changed';
const SETTINGS_SET_VERBOSE_OUTLOOK_LOGGING_CHANGED = 'settings/set-verbose-outlook-logging-changed';
const SETTINGS_SET_DETAILED_EVENTS_LOGGING_CHANGED = 'settings/set-detailed-events-logging-changed';
const SETTINGS_SET_DEBUG_LOGGING_CHANGED = 'settings/set-debug-logging-changed';
const SET_HAS_TRAY_MINIMIZE_NOTIFICATION_SHOWN = 'notifications/set-has-tray-minimize-notification-shown';
const DOWNLOADS_BACK_BUTTON_CLICKED = 'downloads/back-button-clicked';
const WEBVIEW_SERVER_SUPPORTED_VERSIONS_UPDATED = 'webview/server-supported-versions-updated';
const WEBVIEW_SERVER_UNIQUE_ID_UPDATED = 'webview/server-workspace-uid-updated';
const WEBVIEW_SERVER_IS_SUPPORTED_VERSION = 'webview/server-is-supported-version';
const WEBVIEW_SERVER_SUPPORTED_VERSIONS_LOADING = 'webview/server-supported-versions-loading';
const WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR = 'webview/server-supported-versions-error';
const WEBVIEW_SERVER_VERSION_UPDATED = 'webview/version-updated';
const SUPPORTED_VERSION_DIALOG_DISMISS = 'supported-versions-dialog/dismiss';
const WEBVIEW_FORCE_RELOAD_WITH_CACHE_CLEAR = 'webview/force-reload-with-cache-clear';
const OPEN_SERVER_INFO_MODAL = 'server-info-modal/open';
const CLOSE_SERVER_INFO_MODAL = 'server-info-modal/close';

const outlookCalendarSyncInterval = (state = 60, action) => {
  switch (action.type) {
    case SETTINGS_SET_OUTLOOK_CALENDAR_SYNC_INTERVAL_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          outlookCalendarSyncInterval = state
        } = action.payload;
        return outlookCalendarSyncInterval;
      }
    default:
      return state;
  }
};

const outlookCalendarSyncIntervalOverride = (state = null, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          outlookCalendarSyncIntervalOverride = state
        } = action.payload;
        return outlookCalendarSyncIntervalOverride !== null && outlookCalendarSyncIntervalOverride !== undefined ? outlookCalendarSyncIntervalOverride : null;
      }
    default:
      return state;
  }
};

const DEEP_LINKS_SERVER_ADDED = 'deep-links/server-added';
const DEEP_LINKS_SERVER_FOCUSED = 'deep-links/server-focused';

const OUTLOOK_CALENDAR_SET_CREDENTIALS = 'outlook-calendar/set-credentials';
const OUTLOOK_CALENDAR_ASK_CREDENTIALS = 'outlook-calendar/ask-credentials';
const OUTLOOK_CALENDAR_DIALOG_DISMISSED = 'outlook-calendar/dialog-dismissed';
const OUTLOOK_CALENDAR_SAVE_CREDENTIALS = 'outlook-calendar/save-credentials';

const SERVERS_LOADED = 'servers/loaded';
const SERVER_DOCUMENT_VIEWER_OPEN_URL = 'server/document-viewer/open-url';

/* eslint-disable complexity */

const ensureUrlFormat = serverUrl => {
  if (serverUrl) {
    return new URL(serverUrl).href;
  }
  throw new Error('cannot handle null server URLs');
};
const upsert = (state, server) => {
  const index = state.findIndex(({
    url
  }) => url === server.url);
  if (index === -1) {
    return [...state, server];
  }
  return state.map((_server, i) => i === index ? {
    ..._server,
    ...server
  } : _server);
};
const update = (state, server) => {
  const index = state.findIndex(({
    url
  }) => url === server.url);
  if (index === -1) {
    return state;
  }
  return state.map((_server, i) => i === index ? {
    ..._server,
    ...server
  } : _server);
};
const servers = (state = [], action) => {
  switch (action.type) {
    case ADD_SERVER_VIEW_SERVER_ADDED:
    case DEEP_LINKS_SERVER_ADDED:
      {
        const url = action.payload;
        return upsert(state, {
          url,
          title: url
        });
      }
    case SIDE_BAR_REMOVE_SERVER_CLICKED:
      {
        const _url = action.payload;
        return state.filter(({
          url
        }) => url !== _url);
      }
    case SIDE_BAR_SERVERS_SORTED:
      {
        const urls = action.payload;
        return state.sort(({
          url: a
        }, {
          url: b
        }) => urls.indexOf(a) - urls.indexOf(b));
      }
    case WEBVIEW_TITLE_CHANGED:
      {
        const {
          url,
          title = url
        } = action.payload;
        return upsert(state, {
          url,
          title
        });
      }
    case WEBVIEW_PAGE_TITLE_CHANGED:
      {
        const {
          url,
          pageTitle
        } = action.payload;
        return upsert(state, {
          url,
          pageTitle
        });
      }
    case WEBVIEW_SERVER_SUPPORTED_VERSIONS_UPDATED:
      {
        const {
          url,
          supportedVersions,
          source
        } = action.payload;
        return upsert(state, {
          url,
          supportedVersions,
          supportedVersionsSource: source,
          supportedVersionsFetchState: 'success'
        });
      }
    case WEBVIEW_SERVER_SUPPORTED_VERSIONS_LOADING:
      {
        const {
          url
        } = action.payload;
        return upsert(state, {
          url,
          supportedVersionsFetchState: 'loading'
        });
      }
    case WEBVIEW_SERVER_SUPPORTED_VERSIONS_ERROR:
      {
        const {
          url
        } = action.payload;
        return upsert(state, {
          url,
          supportedVersionsFetchState: 'error'
        });
      }
    case SUPPORTED_VERSION_DIALOG_DISMISS:
      {
        const {
          url
        } = action.payload;
        return upsert(state, {
          url,
          expirationMessageLastTimeShown: new Date()
        });
      }
    case WEBVIEW_SERVER_UNIQUE_ID_UPDATED:
      {
        const {
          url,
          uniqueID
        } = action.payload;
        return upsert(state, {
          url,
          uniqueID
        });
      }
    case WEBVIEW_SERVER_IS_SUPPORTED_VERSION:
      {
        const {
          url,
          isSupportedVersion
        } = action.payload;
        return upsert(state, {
          url,
          isSupportedVersion,
          supportedVersionsValidatedAt: new Date()
        });
      }
    case WEBVIEW_SERVER_VERSION_UPDATED:
      {
        const {
          url,
          version
        } = action.payload;
        return upsert(state, {
          url,
          version
        });
      }
    case WEBVIEW_UNREAD_CHANGED:
      {
        const {
          url,
          badge
        } = action.payload;
        return upsert(state, {
          url,
          badge
        });
      }
    case WEBVIEW_USER_LOGGED_IN:
      {
        const {
          url,
          userLoggedIn
        } = action.payload;
        return upsert(state, {
          url,
          userLoggedIn
        });
      }
    case WEBVIEW_ALLOWED_REDIRECTS_CHANGED:
      {
        const {
          url,
          allowedRedirects
        } = action.payload;
        return upsert(state, {
          url,
          allowedRedirects
        });
      }
    case WEBVIEW_SIDEBAR_STYLE_CHANGED:
      {
        const {
          url,
          style
        } = action.payload;
        return upsert(state, {
          url,
          style
        });
      }
    case WEBVIEW_SIDEBAR_CUSTOM_THEME_CHANGED:
      {
        const {
          url,
          customTheme
        } = action.payload;
        return upsert(state, {
          url,
          customTheme
        });
      }
    case WEBVIEW_GIT_COMMIT_HASH_CHANGED:
      {
        const {
          url,
          gitCommitHash
        } = action.payload;
        return upsert(state, {
          url,
          gitCommitHash
        });
      }
    case WEBVIEW_FAVICON_CHANGED:
      {
        const {
          url,
          favicon
        } = action.payload;
        return upsert(state, {
          url,
          favicon
        });
      }
    case WEBVIEW_DID_NAVIGATE:
      {
        const {
          url,
          pageUrl
        } = action.payload;
        if (pageUrl !== null && pageUrl !== undefined && pageUrl.includes(url)) {
          return upsert(state, {
            url,
            lastPath: pageUrl
          });
        }
        return state;
      }
    case WEBVIEW_DID_START_LOADING:
      {
        const {
          url
        } = action.payload;
        return upsert(state, {
          url,
          failed: false
        });
      }
    case WEBVIEW_DID_FAIL_LOAD:
      {
        const {
          url,
          isMainFrame
        } = action.payload;
        if (isMainFrame) {
          return upsert(state, {
            url,
            failed: true
          });
        }
        return state;
      }
    case SERVERS_LOADED:
      {
        const {
          servers = state
        } = action.payload;
        return servers.map(server => ({
          ...server,
          url: ensureUrlFormat(server.url)
        }));
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          servers = state
        } = action.payload;
        return servers.map(server => ({
          ...server,
          url: ensureUrlFormat(server.url),
          documentViewerOpenUrl: '',
          documentViewerFormat: ''
        }));
      }
    case WEBVIEW_READY:
      {
        const {
          url,
          webContentsId
        } = action.payload;
        return update(state, {
          url,
          webContentsId
        });
      }
    case WEBVIEW_ATTACHED:
      {
        const {
          url,
          webContentsId
        } = action.payload;
        return update(state, {
          url,
          webContentsId
        });
      }
    case OUTLOOK_CALENDAR_SAVE_CREDENTIALS:
      {
        const {
          url,
          outlookCredentials
        } = action.payload;
        return upsert(state, {
          url,
          outlookCredentials
        });
      }
    case SERVER_DOCUMENT_VIEWER_OPEN_URL:
      {
        const {
          server,
          documentUrl,
          documentFormat
        } = action.payload;
        return upsert(state, {
          url: server,
          documentViewerOpenUrl: documentUrl,
          documentViewerFormat: documentFormat !== null && documentFormat !== undefined ? documentFormat : ''
        });
      }
    default:
      return state;
  }
};

const availableBrowsers = (state = [], action) => {
  switch (action.type) {
    case SETTINGS_AVAILABLE_BROWSERS_UPDATED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        return state;
      }
    default:
      return state;
  }
};

const currentView = (state = 'add-new-server', action) => {
  switch (action.type) {
    case ADD_SERVER_VIEW_SERVER_ADDED:
    case DEEP_LINKS_SERVER_ADDED:
    case DEEP_LINKS_SERVER_FOCUSED:
    case MENU_BAR_SELECT_SERVER_CLICKED:
    case TOUCH_BAR_SELECT_SERVER_TOUCHED:
    case SIDE_BAR_SERVER_SELECTED:
      {
        const url = action.payload;
        return {
          url
        };
      }
    case WEBVIEW_FOCUS_REQUESTED:
      {
        const {
          url,
          view
        } = action.payload;
        if (view === 'downloads') return 'downloads';
        return {
          url
        };
      }
    case SERVERS_LOADED:
      {
        const {
          selected
        } = action.payload;
        return selected ? {
          url: selected
        } : 'add-new-server';
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          currentView = state
        } = action.payload;
        return currentView;
      }
    case MENU_BAR_ADD_NEW_SERVER_CLICKED:
    case SIDE_BAR_ADD_NEW_SERVER_CLICKED:
      return 'add-new-server';
    case SIDE_BAR_REMOVE_SERVER_CLICKED:
      {
        if (typeof state === 'object' && state.url === action.payload) {
          return 'add-new-server';
        }
        return state;
      }
    case SIDE_BAR_DOWNLOADS_BUTTON_CLICKED:
      return 'downloads';
    case SIDE_BAR_SETTINGS_BUTTON_CLICKED:
      return 'settings';
    case DOWNLOADS_BACK_BUTTON_CLICKED:
      return {
        url: action.payload
      };
    default:
      return state;
  }
};

const initialServerInfoModalState = {
  isOpen: false,
  serverData: null
};
const serverInfoModal = (state = initialServerInfoModalState, action) => {
  switch (action.type) {
    case OPEN_SERVER_INFO_MODAL:
      return {
        isOpen: true,
        serverData: action.payload
      };
    case CLOSE_SERVER_INFO_MODAL:
      return initialServerInfoModalState;
    default:
      return state;
  }
};
const dialogs = (state = {
  serverInfoModal: initialServerInfoModalState
}, action) => {
  switch (action.type) {
    case OPEN_SERVER_INFO_MODAL:
    case CLOSE_SERVER_INFO_MODAL:
      return {
        ...state,
        serverInfoModal: serverInfoModal(state.serverInfoModal, action)
      };
    default:
      return state;
  }
};

const hasHideOnTrayNotificationShown = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.hasHideOnTrayNotificationShown);
    case SET_HAS_TRAY_MINIMIZE_NOTIFICATION_SHOWN:
      return action.payload;
    default:
      return state;
  }
};

const isAddNewServersEnabled = (state = true, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isAddNewServersEnabled);
    default:
      return state;
  }
};

const isDebugLoggingEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_DEBUG_LOGGING_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isDebugLoggingEnabled = state
        } = action.payload;
        return isDebugLoggingEnabled;
      }
    default:
      return state;
  }
};

const isDetailedEventsLoggingEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_DETAILED_EVENTS_LOGGING_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isDetailedEventsLoggingEnabled = state
        } = action.payload;
        return isDetailedEventsLoggingEnabled;
      }
    default:
      return state;
  }
};

const isDeveloperModeEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_DEVELOPER_MODE_ENABLED_CHANGED:
    case MENU_BAR_TOGGLE_IS_DEVELOPER_MODE_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isDeveloperModeEnabled = state
        } = action.payload;
        return isDeveloperModeEnabled;
      }
    default:
      return state;
  }
};

const UPDATE_SKIPPED = 'update/skipped';
const UPDATES_CHECKING_FOR_UPDATE = 'updates/checking-for-update';
const UPDATES_ERROR_THROWN = 'updates/error-thrown';
const UPDATES_NEW_VERSION_AVAILABLE = 'updates/new-version-available';
const UPDATES_NEW_VERSION_NOT_AVAILABLE = 'updates/new-version-not-available';
const UPDATES_READY = 'updates/ready';
const UPDATES_CHANNEL_CHANGED = 'updates/channel-changed';

const isFlashFrameEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isFlashFrameEnabled);
    case UPDATES_READY:
      return action.payload.isFlashFrameEnabled;
    case SETTINGS_SET_FLASHFRAME_OPT_IN_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const isHardwareAccelerationEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isHardwareAccelerationEnabled);
    case UPDATES_READY:
      return action.payload.isHardwareAccelerationEnabled;
    case SETTINGS_SET_HARDWARE_ACCELERATION_OPT_IN_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const isInternalVideoChatWindowEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isInternalVideoChatWindowEnabled);
    case UPDATES_READY:
      return action.payload.isInternalVideoChatWindowEnabled;
    case SETTINGS_SET_INTERNALVIDEOCHATWINDOW_OPT_IN_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const isMenuBarEnabled = (state = true, action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_MENU_BAR_ENABLED_CHANGED:
    case MENU_BAR_TOGGLE_IS_MENU_BAR_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isMenuBarEnabled = state
        } = action.payload;
        return isMenuBarEnabled;
      }
    default:
      return state;
  }
};

const isMessageBoxFocused = (state = false, action) => {
  switch (action.type) {
    case WEBVIEW_MESSAGE_BOX_FOCUSED:
      return true;
    case WEBVIEW_DID_START_LOADING:
    case WEBVIEW_MESSAGE_BOX_BLURRED:
    case WEBVIEW_DID_FAIL_LOAD:
      return false;
    default:
      return state;
  }
};

const isMinimizeOnCloseEnabled = (state = process.platform === 'win32', action) => {
  switch (action.type) {
    case SETTINGS_SET_MINIMIZE_ON_CLOSE_OPT_IN_CHANGED:
      {
        return action.payload;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          isMinimizeOnCloseEnabled = state
        } = action.payload;
        return isMinimizeOnCloseEnabled;
      }
    default:
      return state;
  }
};

const isNTLMCredentialsEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          isNTLMCredentialsEnabled = state
        } = action.payload;
        return isNTLMCredentialsEnabled;
      }
    case SETTINGS_NTLM_CREDENTIALS_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const isReportEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isReportEnabled);
    case UPDATES_READY:
      return action.payload.isReportEnabled;
    case SETTINGS_SET_REPORT_OPT_IN_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const isShowWindowOnUnreadChangedEnabled = (state = false, action) => {
  switch (action.type) {
    case MENU_BAR_TOGGLE_IS_SHOW_WINDOW_ON_UNREAD_CHANGED_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isShowWindowOnUnreadChangedEnabled = state
        } = action.payload;
        return isShowWindowOnUnreadChangedEnabled;
      }
    default:
      return state;
  }
};

const isSideBarEnabled = (state = true, action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_SIDE_BAR_ENABLED_CHANGED:
    case MENU_BAR_TOGGLE_IS_SIDE_BAR_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isSideBarEnabled = state
        } = action.payload;
        return isSideBarEnabled;
      }
    default:
      return state;
  }
};

const isTransparentWindowEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_TRANSPARENT_WINDOW_ENABLED_CHANGED:
      {
        const {
          payload
        } = action;
        if (typeof payload === 'boolean') {
          return payload;
        }
        console.warn(`Invalid payload type for ${SETTINGS_SET_IS_TRANSPARENT_WINDOW_ENABLED_CHANGED}: expected boolean, got ${typeof payload}`);
        return state;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          isTransparentWindowEnabled = state
        } = action.payload;
        return isTransparentWindowEnabled;
      }
    default:
      return state;
  }
};

const isTrayIconEnabled = (state = process.platform !== 'linux', action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_TRAY_ICON_ENABLED_CHANGED:
    case MENU_BAR_TOGGLE_IS_TRAY_ICON_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isTrayIconEnabled = state
        } = action.payload;
        return isTrayIconEnabled;
      }
    default:
      return state;
  }
};

const isVerboseOutlookLoggingEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_VERBOSE_OUTLOOK_LOGGING_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isVerboseOutlookLoggingEnabled = state
        } = action.payload;
        return isVerboseOutlookLoggingEnabled;
      }
    default:
      return state;
  }
};

const isVideoCallDevtoolsAutoOpenEnabled = (state = false, action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_VIDEO_CALL_DEVTOOLS_AUTO_OPEN_ENABLED_CHANGED:
    case MENU_BAR_TOGGLE_IS_VIDEO_CALL_DEVTOOLS_AUTO_OPEN_ENABLED_CLICKED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isVideoCallDevtoolsAutoOpenEnabled = state
        } = action.payload;
        return isVideoCallDevtoolsAutoOpenEnabled;
      }
    default:
      return state;
  }
};

const isVideoCallScreenCaptureFallbackEnabled = (state = false, action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      return Boolean(action.payload.isVideoCallScreenCaptureFallbackEnabled);
    case UPDATES_READY:
      {
        const {
          isVideoCallScreenCaptureFallbackEnabled = state
        } = action.payload;
        return isVideoCallScreenCaptureFallbackEnabled;
      }
    case SETTINGS_SET_IS_VIDEO_CALL_SCREEN_CAPTURE_FALLBACK_ENABLED_CHANGED:
      return action.payload;
    default:
      return state;
  }
};

const isVideoCallWindowPersistenceEnabled = (state = true,
// Enabled by default
action) => {
  switch (action.type) {
    case SETTINGS_SET_IS_VIDEO_CALL_WINDOW_PERSISTENCE_ENABLED_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          isVideoCallWindowPersistenceEnabled = state
        } = action.payload;
        return isVideoCallWindowPersistenceEnabled;
      }
    default:
      return state;
  }
};

const lastSelectedServerUrl = (state = '', action) => {
  switch (action.type) {
    case APP_SETTINGS_LOADED:
      {
        const {
          lastSelectedServerUrl = state,
          servers
        } = action.payload;
        if (state === '' && servers && servers.length > 0) {
          return servers[0].url;
        }
        return lastSelectedServerUrl;
      }
    case SIDE_BAR_SERVER_SELECTED:
      return action.payload;
    default:
      return state;
  }
};

const SCREEN_SHARING_DIALOG_DISMISSED = 'screen-sharing-dialog/dismissed';

const openDialog = (state = null, action) => {
  switch (action.type) {
    case MENU_BAR_ABOUT_CLICKED:
      return 'about';
    case WEBVIEW_SCREEN_SHARING_SOURCE_REQUESTED:
      return 'screen-sharing';
    case UPDATES_NEW_VERSION_AVAILABLE:
      return 'update';
    case CERTIFICATES_CLIENT_CERTIFICATE_REQUESTED:
      return 'select-client-certificate';
    case ABOUT_DIALOG_DISMISSED:
      if (state === 'about') {
        return null;
      }
      return state;
    case OUTLOOK_CALENDAR_ASK_CREDENTIALS:
      return 'outlook-credentials';
    case SCREEN_SHARING_DIALOG_DISMISSED:
    case WEBVIEW_SCREEN_SHARING_SOURCE_RESPONDED:
    case SELECT_CLIENT_CERTIFICATE_DIALOG_CERTIFICATE_SELECTED:
    case SELECT_CLIENT_CERTIFICATE_DIALOG_DISMISSED:
    case UPDATE_DIALOG_DISMISSED:
    case UPDATE_DIALOG_SKIP_UPDATE_CLICKED:
    case UPDATE_DIALOG_REMIND_UPDATE_LATER_CLICKED:
    case UPDATE_DIALOG_INSTALL_BUTTON_CLICKED:
    case OUTLOOK_CALENDAR_DIALOG_DISMISSED:
    case OUTLOOK_CALENDAR_SET_CREDENTIALS:
      return null;
    default:
      return state;
  }
};

const rootWindowIcon = (state = null, action) => {
  switch (action.type) {
    case ROOT_WINDOW_ICON_CHANGED:
      {
        return action.payload;
      }
    default:
      return state;
  }
};

const rootWindowState = (state = {
  focused: true,
  visible: true,
  maximized: false,
  minimized: false,
  fullscreen: false,
  normal: true,
  bounds: {
    x: undefined,
    y: undefined,
    width: 1000,
    height: 600
  }
}, action) => {
  switch (action.type) {
    case ROOT_WINDOW_STATE_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          rootWindowState = state
        } = action.payload;
        return rootWindowState;
      }
    default:
      return state;
  }
};

const selectedBrowser = (state = null, action) => {
  switch (action.type) {
    case SETTINGS_SELECTED_BROWSER_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          selectedBrowser = state
        } = action.payload;
        return selectedBrowser;
      }
    default:
      return state;
  }
};

const isValidTheme = value => value === 'auto' || value === 'light' || value === 'dark';
const userThemePreference = (state = 'auto', action) => {
  switch (action.type) {
    case SETTINGS_USER_THEME_PREFERENCE_CHANGED:
      if (isValidTheme(action.payload)) {
        return action.payload;
      }
      console.warn(`Invalid payload for ${SETTINGS_USER_THEME_PREFERENCE_CHANGED}: ${action.payload}`);
      return state;
    case APP_SETTINGS_LOADED:
      {
        const {
          userThemePreference = state
        } = action.payload;
        if (isValidTheme(userThemePreference)) {
          return userThemePreference;
        }
        console.warn(`Invalid userThemePreference in settings: ${userThemePreference}`);
        return state;
      }
    default:
      return state;
  }
};

const videoCallWindowState = (state = {
  focused: true,
  visible: true,
  maximized: false,
  minimized: false,
  fullscreen: false,
  normal: true,
  bounds: {
    x: undefined,
    y: undefined,
    width: 0,
    height: 0
  }
}, action) => {
  switch (action.type) {
    case VIDEO_CALL_WINDOW_STATE_CHANGED:
      return action.payload;
    case APP_SETTINGS_LOADED:
      {
        const {
          videoCallWindowState = state
        } = action.payload;
        return videoCallWindowState;
      }
    default:
      return state;
  }
};

const doCheckForUpdatesOnStartup = (state = true, action) => {
  switch (action.type) {
    case UPDATES_READY:
      {
        const {
          doCheckForUpdatesOnStartup
        } = action.payload;
        return doCheckForUpdatesOnStartup;
      }
    case ABOUT_DIALOG_TOGGLE_UPDATE_ON_START:
      {
        const doCheckForUpdatesOnStartup = action.payload;
        return doCheckForUpdatesOnStartup;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          doCheckForUpdatesOnStartup = state
        } = action.payload;
        return doCheckForUpdatesOnStartup;
      }
    default:
      return state;
  }
};
const isCheckingForUpdates = (state = false, action) => {
  switch (action.type) {
    case UPDATES_CHECKING_FOR_UPDATE:
      return true;
    case UPDATES_ERROR_THROWN:
      return false;
    case UPDATES_NEW_VERSION_NOT_AVAILABLE:
      return false;
    case UPDATES_NEW_VERSION_AVAILABLE:
      return false;
    default:
      return state;
  }
};
const isEachUpdatesSettingConfigurable = (state = true, action) => {
  switch (action.type) {
    case UPDATES_READY:
      {
        const {
          isEachUpdatesSettingConfigurable
        } = action.payload;
        return isEachUpdatesSettingConfigurable;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          isEachUpdatesSettingConfigurable = state
        } = action.payload;
        return isEachUpdatesSettingConfigurable;
      }
    default:
      return state;
  }
};
const isUpdatingAllowed = (state = true, action) => {
  switch (action.type) {
    case UPDATES_READY:
      {
        const {
          isUpdatingAllowed
        } = action.payload;
        return isUpdatingAllowed;
      }
    default:
      return state;
  }
};
const isUpdatingEnabled = (state = true, action) => {
  switch (action.type) {
    case UPDATES_READY:
      {
        const {
          isUpdatingEnabled
        } = action.payload;
        return isUpdatingEnabled;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          isUpdatingEnabled = state
        } = action.payload;
        return isUpdatingEnabled;
      }
    default:
      return state;
  }
};
const newUpdateVersion = (state = null, action) => {
  switch (action.type) {
    case UPDATES_NEW_VERSION_AVAILABLE:
      {
        const newUpdateVersion = action.payload;
        return newUpdateVersion;
      }
    case UPDATES_NEW_VERSION_NOT_AVAILABLE:
    case UPDATE_SKIPPED:
      {
        return null;
      }
    default:
      return state;
  }
};
const skippedUpdateVersion = (state = null, action) => {
  switch (action.type) {
    case UPDATES_READY:
      {
        const {
          skippedUpdateVersion
        } = action.payload;
        return skippedUpdateVersion;
      }
    case UPDATE_SKIPPED:
      {
        const skippedUpdateVersion = action.payload;
        return skippedUpdateVersion;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          skippedUpdateVersion = state
        } = action.payload;
        return skippedUpdateVersion;
      }
    default:
      return state;
  }
};
const updateError = (state = null, action) => {
  switch (action.type) {
    case UPDATES_CHECKING_FOR_UPDATE:
      return null;
    case UPDATES_ERROR_THROWN:
      return action.payload;
    case UPDATES_NEW_VERSION_NOT_AVAILABLE:
      return null;
    case UPDATES_NEW_VERSION_AVAILABLE:
      return null;
    default:
      return state;
  }
};
const updateChannel = (state = 'latest', action) => {
  switch (action.type) {
    case ABOUT_DIALOG_UPDATE_CHANNEL_CHANGED:
    case UPDATES_CHANNEL_CHANGED:
      {
        return action.payload;
      }
    case UPDATES_READY:
      {
        const {
          updateChannel
        } = action.payload;
        return updateChannel;
      }
    case APP_SETTINGS_LOADED:
      {
        const {
          updateChannel = state
        } = action.payload;
        return updateChannel;
      }
    default:
      return state;
  }
};

const rootReducer = redux.combineReducers({
  allowedJitsiServers,
  allowInsecureOutlookConnections,
  outlookCalendarSyncInterval,
  outlookCalendarSyncIntervalOverride,
  appPath,
  appVersion,
  availableBrowsers,
  clientCertificates,
  currentView,
  dialogs,
  doCheckForUpdatesOnStartup,
  downloads,
  externalProtocols,
  isCheckingForUpdates,
  isEachUpdatesSettingConfigurable,
  isMenuBarEnabled,
  isMessageBoxFocused,
  isShowWindowOnUnreadChangedEnabled,
  isSideBarEnabled,
  isTrayIconEnabled,
  isMinimizeOnCloseEnabled,
  isUpdatingAllowed,
  isUpdatingEnabled,
  mainWindowTitle,
  machineTheme,
  newUpdateVersion,
  openDialog,
  rootWindowIcon,
  rootWindowState,
  selectedBrowser,
  servers,
  userThemePreference,
  skippedUpdateVersion,
  trustedCertificates,
  notTrustedCertificates,
  updateError,
  isReportEnabled,
  isFlashFrameEnabled,
  isHardwareAccelerationEnabled,
  isInternalVideoChatWindowEnabled,
  isAddNewServersEnabled,
  hasHideOnTrayNotificationShown,
  lastSelectedServerUrl,
  allowedNTLMCredentialsDomains,
  isNTLMCredentialsEnabled,
  videoCallWindowState,
  isVideoCallWindowPersistenceEnabled,
  isDeveloperModeEnabled,
  isDebugLoggingEnabled,
  isDetailedEventsLoggingEnabled,
  isVerboseOutlookLoggingEnabled,
  updateChannel,
  screenCaptureFallbackForced,
  isVideoCallDevtoolsAutoOpenEnabled,
  isTransparentWindowEnabled,
  isVideoCallScreenCaptureFallbackEnabled
});

let reduxStore;
let lastAction;
const catchLastAction = () => next => action => {
  lastAction = action;
  return next(action);
};
const createRendererReduxStore = async () => {
  const initialState = await getInitialState();
  const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || redux.compose;
  const enhancers = composeEnhancers(redux.applyMiddleware(forwardToMain, catchLastAction));
  reduxStore = redux.createStore(rootReducer, initialState, enhancers);
  return reduxStore;
};
const dispatch = action => {
  if (!reduxStore) return;
  reduxStore.dispatch(action);
};
const select = selector => selector(reduxStore.getState());
const safeSelect = selector => {
  if (!reduxStore) return undefined;
  return selector(reduxStore.getState());
};
const watch = (selector, watcher) => {
  if (!reduxStore) {
    console.warn('[store] watch() called before store initialized');
    return () => undefined;
  }
  const initial = select(selector);
  watcher(initial, undefined);
  let prev = initial;
  return reduxStore.subscribe(() => {
    const curr = select(selector);
    if (Object.is(prev, curr)) {
      return;
    }
    watcher(curr, prev);
    prev = curr;
  });
};
const listen = (typeOrPredicate, listener) => {
  if (!reduxStore) return () => undefined;
  const effectivePredicate = typeof typeOrPredicate === 'function' ? typeOrPredicate : action => action.type === typeOrPredicate;
  return reduxStore.subscribe(() => {
    if (!effectivePredicate(lastAction)) {
      return;
    }
    listener(lastAction);
  });
};

// const isResponseTo = <Response extends RootAction>(id: unknown, type: Response['type']) =>
//   (action: RootAction): action is Response =>
//     isResponse(action) && action.type === type && action.meta.id === id;

const request = (requestAction, ...types) => new Promise((resolve, reject) => {
  if (!reduxStore) {
    reject(new Error('Store not initialized'));
    return;
  }
  const id = Math.random().toString(36).slice(2);
  const unsubscribe = listen(isResponseTo(id, ...types), action => {
    unsubscribe();
    if (isErrored(action)) {
      reject(action.payload);
      return;
    }
    if (hasPayload(action)) {
      resolve(action.payload);
    }
  });
  dispatch({
    ...requestAction,
    meta: {
      request: true,
      id
    }
  });
});

const NOTIFICATIONS_CREATE_REQUESTED = 'notifications/create-requested';
const NOTIFICATIONS_CREATE_RESPONDED = 'notifications/create-responded';
const NOTIFICATIONS_NOTIFICATION_ACTIONED = 'notifications/notification-actioned';
const NOTIFICATIONS_NOTIFICATION_CLICKED = 'notifications/notification-clicked';
const NOTIFICATIONS_NOTIFICATION_CLOSED = 'notifications/notification-closed';
const NOTIFICATIONS_NOTIFICATION_DISMISSED = 'notifications/notification-dismissed';
const NOTIFICATIONS_NOTIFICATION_REPLIED = 'notifications/notification-replied';
const NOTIFICATIONS_NOTIFICATION_SHOWN = 'notifications/notification-shown';

const normalizeIconUrl = iconUrl => {
  if (/^data:/.test(iconUrl)) {
    return iconUrl;
  }
  if (!/^https?:\/\//.test(iconUrl)) {
    return getAbsoluteUrl(iconUrl);
  }
  return iconUrl;
};
const eventHandlers = new Map();
const createNotification = async ({
  title,
  icon,
  onEvent,
  ...options
}) => {
  const id = await request({
    type: NOTIFICATIONS_CREATE_REQUESTED,
    payload: {
      title,
      ...(icon ? {
        icon: normalizeIconUrl(icon)
      } : {}),
      ...options
    }
  }, NOTIFICATIONS_CREATE_RESPONDED);
  eventHandlers.set(id, event => onEvent === null || onEvent === undefined ? undefined : onEvent({
    type: event.type,
    detail: event.detail
  }));
  return id;
};
const destroyNotification = id => {
  dispatch({
    type: NOTIFICATIONS_NOTIFICATION_DISMISSED,
    payload: {
      id
    }
  });
  eventHandlers.delete(id);
};
const dispatchCustomNotification = async options => {
  const {
    id,
    payload,
    type
  } = options;
  const notificationId = id || Math.random().toString(36).slice(2);
  return createNotification({
    title: payload.title,
    body: payload.body,
    icon: payload.avatar,
    tag: notificationId,
    requireInteraction: payload.requireInteraction,
    notificationType: type
  });
};
const closeCustomNotification = id => {
  destroyNotification(id);
};
const listenToNotificationsRequests = () => {
  listen(NOTIFICATIONS_NOTIFICATION_SHOWN, action => {
    const {
      payload: {
        id
      }
    } = action;
    const eventHandler = eventHandlers.get(id);
    eventHandler === null || eventHandler === undefined || eventHandler({
      type: 'show'
    });
  });
  listen(NOTIFICATIONS_NOTIFICATION_CLOSED, action => {
    const {
      payload: {
        id
      }
    } = action;
    const eventHandler = eventHandlers.get(id);
    eventHandler === null || eventHandler === undefined || eventHandler({
      type: 'close'
    });
    eventHandlers.delete(id);
  });
  listen(NOTIFICATIONS_NOTIFICATION_CLICKED, action => {
    const {
      payload: {
        id,
        serverUrl,
        category
      }
    } = action;
    if (category === 'DOWNLOADS') {
      dispatch({
        type: SIDE_BAR_DOWNLOADS_BUTTON_CLICKED
      });
    } else {
      dispatch({
        type: WEBVIEW_FOCUS_REQUESTED,
        payload: {
          url: serverUrl || getServerUrl(),
          view: 'server'
        }
      });
    }
    const eventHandler = eventHandlers.get(id);
    eventHandler === null || eventHandler === undefined || eventHandler({
      type: 'click'
    });
  });
  listen(NOTIFICATIONS_NOTIFICATION_REPLIED, action => {
    const {
      payload: {
        id,
        reply
      }
    } = action;
    const eventHandler = eventHandlers.get(id);
    eventHandler === null || eventHandler === undefined || eventHandler({
      type: 'reply',
      detail: {
        reply
      }
    });
  });
  listen(NOTIFICATIONS_NOTIFICATION_ACTIONED, action => {
    const {
      payload: {
        id,
        index
      }
    } = action;
    const eventHandler = eventHandlers.get(id);
    eventHandler === null || eventHandler === undefined || eventHandler({
      type: 'action',
      detail: {
        index
      }
    });
  });
};

const handleGetSourceIdEvent = async () => {
  try {
    var _window$top;
    const sourceId = await request({
      type: WEBVIEW_SCREEN_SHARING_SOURCE_REQUESTED
    }, WEBVIEW_SCREEN_SHARING_SOURCE_RESPONDED);
    (_window$top = window.top) === null || _window$top === void 0 || _window$top.postMessage({
      sourceId
    }, '*');
  } catch (error) {
    var _window$top2;
    (_window$top2 = window.top) === null || _window$top2 === undefined || _window$top2.postMessage({
      sourceId: 'PermissionDeniedError'
    }, '*');
  }
};
const listenToScreenSharingRequests = () => {
  window.addEventListener('get-sourceId', handleGetSourceIdEvent);
};

const getOutlookEvents = async date => {
  console.info('[OutlookCalendar] Preload: Getting Outlook events for date:', date.toISOString());
  try {
    const response = await electron.ipcRenderer.invoke('outlook-calendar/get-events', date);
    console.info('[OutlookCalendar] Preload: Successfully got Outlook events response:', response);
    return response;
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error('[OutlookCalendar] Preload: Failed to get Outlook events:', {
      date: date.toISOString(),
      error: errorMessage
    });
    throw new Error(`Failed to get Outlook events: ${errorMessage}`);
  }
};
const setOutlookExchangeUrl = (url, userId) => {
  console.info('[OutlookCalendar] Preload: Setting Exchange URL:', {
    url,
    userId
  });
  electron.ipcRenderer.invoke('outlook-calendar/set-exchange-url', url, userId).then(() => {
    console.info('[OutlookCalendar] Preload: Successfully set Exchange URL');
  }).catch(error => {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error('[OutlookCalendar] Preload: Failed to set Exchange URL:', {
      url,
      userId,
      error: errorMessage
    });
  });
};
const hasOutlookCredentials = async () => {
  console.info('[OutlookCalendar] Preload: Checking if Outlook credentials exist');
  try {
    const result = await electron.ipcRenderer.invoke('outlook-calendar/has-credentials');
    console.info('[OutlookCalendar] Preload: Credentials check result:', result);
    return result;
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error('[OutlookCalendar] Preload: Failed to check credentials:', errorMessage);
    return false;
  }
};
const clearOutlookCredentials = () => {
  console.info('[OutlookCalendar] Preload: Clearing Outlook credentials');
  electron.ipcRenderer.invoke('outlook-calendar/clear-credentials').then(() => {
    console.info('[OutlookCalendar] Preload: Successfully cleared credentials');
  }).catch(error => {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error('[OutlookCalendar] Preload: Failed to clear credentials:', errorMessage);
  });
};
const setUserToken = (token, userId) => {
  console.info('[OutlookCalendar] Preload: Setting user token for userId:', userId);
  electron.ipcRenderer.invoke('outlook-calendar/set-user-token', token, userId).then(() => {
    console.info('[OutlookCalendar] Preload: Successfully set user token');
  }).catch(error => {
    const errorMessage = error instanceof Error ? error.message : String(error);
    console.error('[OutlookCalendar] Preload: Failed to set user token:', {
      userId,
      error: errorMessage
    });
  });
};

const SYSTEM_LOCKING_SCREEN = 'system/locking-screen';
const SYSTEM_SUSPENDING = 'system/suspending';

let detachCallbacks;
const attachCallbacks = ({
  isAutoAwayEnabled,
  idleThreshold,
  setUserOnline
}) => {
  const unsubscribeFromPowerMonitorEvents = listen(action => [SYSTEM_SUSPENDING, SYSTEM_LOCKING_SCREEN].includes(action.type), () => {
    if (!isAutoAwayEnabled) {
      return;
    }
    setUserOnline(false);
  });
  let pollingTimer;
  let prevState;
  const pollSystemIdleState = async () => {
    if (!isAutoAwayEnabled || !idleThreshold) {
      return;
    }
    pollingTimer = setTimeout(pollSystemIdleState, 2000);
    const state = await invoke('power-monitor/get-system-idle-state', idleThreshold);
    if (prevState === state) {
      return;
    }
    const isOnline = state === 'active' || state === 'unknown';
    setUserOnline(isOnline);
    prevState = state;
  };
  pollSystemIdleState();
  return () => {
    unsubscribeFromPowerMonitorEvents();
    clearTimeout(pollingTimer);
  };
};
const setUserPresenceDetection = options => {
  var _detachCallbacks;
  (_detachCallbacks = detachCallbacks) === null || _detachCallbacks === undefined || _detachCallbacks();
  detachCallbacks = attachCallbacks(options);
};

const setBadge = badge => {
  dispatch({
    type: WEBVIEW_UNREAD_CHANGED,
    payload: {
      url: getServerUrl(),
      badge
    }
  });
};

const writeTextToClipboard = text => {
  electron.clipboard.writeText(text);
};

const openDocumentViewer = (url, format, options) => {
  electron.ipcRenderer.invoke('document-viewer/open-window', url, format, options);
};

const FAVICON_SIZE = 100;
let imageElement;
const getImageElement = () => {
  if (!imageElement) {
    const canvas = document.createElement('canvas');
    canvas.width = FAVICON_SIZE;
    canvas.height = FAVICON_SIZE;
    const ctx = canvas.getContext('2d');
    if (!ctx) {
      throw new Error('failed to create canvas 2d context');
    }
    imageElement = new Image();
    const handleImageLoadEvent = () => {
      ctx.clearRect(0, 0, FAVICON_SIZE, FAVICON_SIZE);
      ctx.drawImage(imageElement, 0, 0, FAVICON_SIZE, FAVICON_SIZE);
      dispatch({
        type: WEBVIEW_FAVICON_CHANGED,
        payload: {
          url: getServerUrl(),
          favicon: canvas.toDataURL()
        }
      });
    };
    imageElement.addEventListener('load', handleImageLoadEvent, {
      passive: true
    });
  }
  return imageElement;
};
const setFavicon = faviconUrl => {
  if (typeof faviconUrl !== 'string') {
    return;
  }
  const imageElement = getImageElement();
  imageElement.src = getAbsoluteUrl(faviconUrl);
};

const setGitCommitHash = gitCommitHash => {
  dispatch({
    type: WEBVIEW_GIT_COMMIT_HASH_CHECK,
    payload: {
      url: getServerUrl(),
      gitCommitHash
    }
  });
};

const readSetting = key => {
  try {
    const filePath = path__default.default.join(electron.app.getPath('userData'), 'config.json');
    const content = fs__default.default.readFileSync(filePath, 'utf8');
    const json = JSON.parse(content);
    return json[key];
  } catch (e) {
    return null;
  }
};

// Cache browsers to avoid repeatedly fetching them
let cachedBrowsers = null;
let browserLoadPromise = null;

/**
 * Lazy load browsers asynchronously
 * This ensures we don't slow down app startup
 */
const loadBrowsersLazy = () => {
  if (cachedBrowsers) {
    return Promise.resolve(cachedBrowsers);
  }
  if (!browserLoadPromise) {
    // Start loading browsers asynchronously after a delay to not block the app startup
    browserLoadPromise = new Promise(resolve => {
      // Delay browser detection for 2 seconds after this function is first called
      // to avoid slowing down app startup and initial interactions
      setTimeout(async () => {
        try {
          const browsers = await detectBrowsers.getAvailableBrowsers();
          cachedBrowsers = browsers;
          const browserIds = browsers.map(browser => browser.browser);
          if (browserIds.length > 0) {
            dispatch({
              type: SETTINGS_AVAILABLE_BROWSERS_UPDATED,
              payload: browserIds
            });
          }
          resolve(browsers);
        } catch (error) {
          console.error('Error detecting browsers:', error);
          resolve([]);
        }
      }, 2000);
    });
  }
  return browserLoadPromise;
};

/**
 * Launches a URL in the selected browser from settings or falls back to system default
 *
 * @param url The URL to open
 * @returns Promise that resolves when the browser is launched
 */
const openExternal = async url => {
  // Get the selected browser from settings
  const selectedBrowser = readSetting('selectedBrowser');

  // If no specific browser is selected, use the system default
  if (!selectedBrowser) {
    return electron.shell.openExternal(url);
  }
  try {
    // Lazy load browsers when needed
    const browsers = await loadBrowsersLazy();

    // Find the selected browser in the available browsers
    const browser = browsers.find(browser => browser.browser === selectedBrowser);
    if (browser) {
      // Launch the selected browser with the URL
      return detectBrowsers.launchBrowser(browser, url);
    }
    // If the selected browser isn't available, fall back to system default
    console.warn(`Selected browser "${selectedBrowser}" not found, using system default.`);
    return electron.shell.openExternal(url);
  } catch (error) {
    console.error('Error launching browser:', error);
    // Fall back to shell.openExternal on error
    return electron.shell.openExternal(url);
  }
};

const getInternalVideoChatWindowEnabled = () => {
  var _safeSelect;
  return (_safeSelect = safeSelect(({
    isInternalVideoChatWindowEnabled
  }) => isInternalVideoChatWindowEnabled)) !== null && _safeSelect !== undefined ? _safeSelect : false;
};
const getCredentialsForPexip = options => {
  if ((options === null || options === undefined ? undefined : options.providerName) !== 'pexip') {
    return options;
  }
  const authToken = localStorage.getItem('Meteor.loginToken');
  const userId = localStorage.getItem('Meteor.userId');
  if (authToken && userId) {
    return {
      ...options,
      credentials: {
        userId,
        authToken
      }
    };
  }
  return options;
};
const openInternalVideoChatWindow = (url, options) => {
  const validUrl = new URL(url);
  const allowedProtocols = ['http:', 'https:'];
  if (!allowedProtocols.includes(validUrl.protocol)) {
    return;
  }
  if (!process.mas && getInternalVideoChatWindowEnabled()) {
    const enrichedOptions = getCredentialsForPexip(options);
    switch (options === null || options === undefined ? undefined : options.providerName) {
      case 'jitsi':
        // window.open(validUrl.href, 'Video Call', 'scrollbars=true');
        // We will open Jitsi on browser instead of opening a new window for compatibility from their side
        electron.ipcRenderer.invoke('video-call-window/open-window', validUrl.href, enrichedOptions);
        break;
      case 'googlemeet':
        openExternal(validUrl.href);
        break;
      default:
        electron.ipcRenderer.invoke('video-call-window/open-window', validUrl.href, enrichedOptions);
        break;
    }
  } else {
    openExternal(validUrl.href);
  }
};

const openInBrowser = url => {
  try {
    const parsed = new URL(url);
    if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
      console.warn(`[RocketChatDesktop.openInBrowser] blocked non-http(s) URL: ${parsed.protocol}`);
      return;
    }
    electron.ipcRenderer.invoke('browser/open-url', parsed.toString());
  } catch (error) {
    console.warn('[RocketChatDesktop.openInBrowser] invalid URL:', error);
  }
};

const reloadServer = () => {
  const url = getServerUrl();

  // Dispatch action to trigger force reload with cache clear
  dispatch({
    type: WEBVIEW_FORCE_RELOAD_WITH_CACHE_CLEAR,
    payload: url
  });
};

let timer;
let prevBackground;
let prevColor;
let prevBorder;
let serverVersion;
function versionIsGreaterOrEqualsTo(version1, version2) {
  var _version1$match, _version2$match;
  const v1 = ((_version1$match = version1.match(/\d+/g)) === null || _version1$match === undefined ? undefined : _version1$match.map(Number)) || [];
  const v2 = ((_version2$match = version2.match(/\d+/g)) === null || _version2$match === undefined ? undefined : _version2$match.map(Number)) || [];
  for (let i = 0; i < 3; i++) {
    const n1 = v1[i] || 0;
    const n2 = v2[i] || 0;
    if (n1 > n2) {
      return true;
    }
    if (n1 < n2) {
      return false;
    }
  }
  return true;
}
const pollSidebarStyle = (referenceElement, emit) => {
  clearTimeout(timer);
  document.body.append(referenceElement);
  const {
    background,
    color,
    border
  } = window.getComputedStyle(referenceElement);
  referenceElement.remove();
  const newBgg = prevBackground !== background ? background : prevBackground;
  const newColor = prevColor !== color ? color : prevColor;
  const newBorder = prevBorder !== border ? border : prevBorder;
  if (prevBackground !== background || prevColor !== color || newBorder !== border) {
    emit({
      background: newBgg,
      color: newColor,
      border: newBorder
    });
    prevBackground = background;
    prevColor = color;
    prevBorder = border;
  }
  timer = setTimeout(() => pollSidebarStyle(referenceElement, emit), 5000);
};
let element;
const getElement = () => {
  if (!element) {
    element = document.createElement('div');
    element.style.backgroundColor = 'var(--sidebar-background)';
    element.style.color = 'var(--sidebar-item-text-color)';
    element.style.display = 'none';
    if (versionIsGreaterOrEqualsTo(serverVersion, '6.3.0')) {
      element.classList.add('rcx-sidebar--main');
      element.style.border = '1px solid var(--sidebar-border-color)';
    } else {
      element.classList.add('sidebar');
    }
  }
  return element;
};
const setServerVersionToSidebar = version => {
  serverVersion = version;
};
const setBackground = imageUrl => {
  const element = getElement();
  element.style.backgroundImage = imageUrl ? `url(${JSON.stringify(getAbsoluteUrl(imageUrl))})` : 'none';
  pollSidebarStyle(element, sideBarStyle => {
    dispatch({
      type: WEBVIEW_SIDEBAR_STYLE_CHANGED,
      payload: {
        url: getServerUrl(),
        style: sideBarStyle
      }
    });
  });
};
const setSidebarCustomTheme = customTheme => {
  dispatch({
    type: WEBVIEW_SIDEBAR_CUSTOM_THEME_CHANGED,
    payload: {
      url: getServerUrl(),
      customTheme
    }
  });
};

const setUserThemeAppearance = _themeAppearance => {
  // No-op: Theme appearance is now managed globally via userThemePreference
  // This function is kept for backwards compatibility with the desktop-api interface
};

const setTitle = title => {
  if (typeof title !== 'string') {
    return;
  }
  const url = getServerUrl();
  if (title === 'Rocket.Chat' && new URL(url).host !== 'open.rocket.chat') {
    dispatch({
      type: WEBVIEW_TITLE_CHANGED,
      payload: {
        url,
        title: `${title} - ${url}`
      }
    });
    return;
  }
  dispatch({
    type: WEBVIEW_TITLE_CHANGED,
    payload: {
      url,
      title
    }
  });
};

const setUserLoggedIn = userLoggedIn => {
  dispatch({
    type: WEBVIEW_USER_LOGGED_IN,
    payload: {
      url: getServerUrl(),
      userLoggedIn
    }
  });
};

let serverInfo;
let cb = _serverInfo => undefined;
const RocketChatDesktop = {
  onReady: c => {
    if (serverInfo) {
      c(serverInfo);
    }
    cb = c;
  },
  setServerInfo: _serverInfo => {
    serverInfo = _serverInfo;
    cb(_serverInfo);
    setServerVersionToSidebar(_serverInfo.version);
  },
  setUrlResolver,
  setBadge,
  setFavicon,
  setBackground,
  setTitle,
  setUserPresenceDetection,
  setUserLoggedIn,
  setUserThemeAppearance,
  createNotification,
  destroyNotification,
  dispatchCustomNotification,
  closeCustomNotification,
  getInternalVideoChatWindowEnabled,
  openInternalVideoChatWindow,
  setGitCommitHash,
  writeTextToClipboard,
  getOutlookEvents,
  setOutlookExchangeUrl,
  hasOutlookCredentials,
  clearOutlookCredentials,
  setUserToken,
  setSidebarCustomTheme,
  openDocumentViewer,
  openInBrowser,
  reloadServer
};

function debounce(cb, wait = 20) {
  let h;
  const callable = (...args) => {
    h && clearTimeout(h);
    h = setTimeout(() => cb(...args), wait);
  };
  return callable;
}

let focusedMessageBoxInput = null;
const handleFocusEvent = event => {
  if (!(event.target instanceof Element)) {
    return;
  }
  if (!event.target.classList.contains('js-input-message')) {
    return;
  }
  focusedMessageBoxInput = event.target;
  dispatch({
    type: WEBVIEW_MESSAGE_BOX_FOCUSED
  });
};
const handleBlurEvent = event => {
  if (!(event.target instanceof Element)) {
    return;
  }
  if (!event.target.classList.contains('js-input-message')) {
    return;
  }
  focusedMessageBoxInput = null;
  dispatch({
    type: WEBVIEW_MESSAGE_BOX_BLURRED
  });
};
const listenToMessageBoxEvents = () => {
  listen(TOUCH_BAR_FORMAT_BUTTON_TOUCHED, action => {
    if (!focusedMessageBoxInput) {
      return;
    }
    const {
      payload: buttonId
    } = action;
    const ancestor = focusedMessageBoxInput.closest('.rc-message-box');
    const button = ancestor === null || ancestor === undefined ? undefined : ancestor.querySelector(`[data-id='${buttonId}']`);
    button === null || button === undefined || button.click();
  });
  document.addEventListener('focus', handleFocusEvent, true);
  document.addEventListener('blur', handleBlurEvent, true);
};

const selectIsSideBarVisible = ({
  servers,
  isSideBarEnabled
}) => servers.length > 0 && isSideBarEnabled;
const handleTrafficLightsSpacing = () => {
  if (process.platform !== 'darwin') {
    return;
  }
  const style = document.getElementById('sidebar-padding') || document.createElement('style');
  style.id = 'sidebar-padding';
  document.head.append(style);
  watch(selectIsSideBarVisible, isSideBarVisible => {
    style.innerHTML = `
      .sidebar {
        padding-top: ${isSideBarVisible ? 0 : '10px'} !important;
        transition: padding-top 230ms ease-in-out !important;
      }
    `;
  });
};

const whenReady = () => new Promise(resolve => {
  if (document.readyState === 'complete') {
    resolve();
    return;
  }
  const handleReadyStateChange = () => {
    if (document.readyState !== 'complete') {
      return;
    }
    document.removeEventListener('readystatechange', handleReadyStateChange);
    resolve();
  };
  document.addEventListener('readystatechange', handleReadyStateChange);
});

function getDefaultExportFromCjs (x) {
	return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}

var renderer$1 = {exports: {}};

var scope = scopeFactory$1;
function scopeFactory$1(logger) {
  return Object.defineProperties(scope, {
    defaultLabel: {
      value: '',
      writable: true
    },
    labelPadding: {
      value: true,
      writable: true
    },
    maxLabelLength: {
      value: 0,
      writable: true
    },
    labelLength: {
      get() {
        switch (typeof scope.labelPadding) {
          case 'boolean':
            return scope.labelPadding ? scope.maxLabelLength : 0;
          case 'number':
            return scope.labelPadding;
          default:
            return 0;
        }
      }
    }
  });
  function scope(label) {
    scope.maxLabelLength = Math.max(scope.maxLabelLength, label.length);
    const newScope = {};
    for (const level of logger.levels) {
      newScope[level] = (...d) => logger.logData(d, {
        level,
        scope: label
      });
    }
    newScope.log = newScope.info;
    return newScope;
  }
}

let Buffering$1 = class Buffering {
  constructor({
    processMessage
  }) {
    this.processMessage = processMessage;
    this.buffer = [];
    this.enabled = false;
    this.begin = this.begin.bind(this);
    this.commit = this.commit.bind(this);
    this.reject = this.reject.bind(this);
  }
  addMessage(message) {
    this.buffer.push(message);
  }
  begin() {
    this.enabled = [];
  }
  commit() {
    this.enabled = false;
    this.buffer.forEach(item => this.processMessage(item));
    this.buffer = [];
  }
  reject() {
    this.enabled = false;
    this.buffer = [];
  }
};
var Buffering_1 = Buffering$1;

const scopeFactory = scope;
const Buffering = Buffering_1;

/**
 * @property {Function} error
 * @property {Function} warn
 * @property {Function} info
 * @property {Function} verbose
 * @property {Function} debug
 * @property {Function} silly
 */
class Logger {
  static instances = {};
  dependencies = {};
  errorHandler = null;
  eventLogger = null;
  functions = {};
  hooks = [];
  isDev = false;
  levels = null;
  logId = null;
  scope = null;
  transports = {};
  variables = {};
  constructor({
    allowUnknownLevel = false,
    dependencies = {},
    errorHandler,
    eventLogger,
    initializeFn,
    isDev = false,
    levels = ['error', 'warn', 'info', 'verbose', 'debug', 'silly'],
    logId,
    transportFactories = {},
    variables
  } = {}) {
    this.addLevel = this.addLevel.bind(this);
    this.create = this.create.bind(this);
    this.initialize = this.initialize.bind(this);
    this.logData = this.logData.bind(this);
    this.processMessage = this.processMessage.bind(this);
    this.allowUnknownLevel = allowUnknownLevel;
    this.buffering = new Buffering(this);
    this.dependencies = dependencies;
    this.initializeFn = initializeFn;
    this.isDev = isDev;
    this.levels = levels;
    this.logId = logId;
    this.scope = scopeFactory(this);
    this.transportFactories = transportFactories;
    this.variables = variables || {};
    for (const name of this.levels) {
      this.addLevel(name, false);
    }
    this.log = this.info;
    this.functions.log = this.log;
    this.errorHandler = errorHandler;
    errorHandler?.setOptions({
      ...dependencies,
      logFn: this.error
    });
    this.eventLogger = eventLogger;
    eventLogger?.setOptions({
      ...dependencies,
      logger: this
    });
    for (const [name, factory] of Object.entries(transportFactories)) {
      this.transports[name] = factory(this, dependencies);
    }
    Logger.instances[logId] = this;
  }
  static getInstance({
    logId
  }) {
    return this.instances[logId] || this.instances.default;
  }
  addLevel(level, index = this.levels.length) {
    if (index !== false) {
      this.levels.splice(index, 0, level);
    }
    this[level] = (...args) => this.logData(args, {
      level
    });
    this.functions[level] = this[level];
  }
  catchErrors(options) {
    this.processMessage({
      data: ['log.catchErrors is deprecated. Use log.errorHandler instead'],
      level: 'warn'
    }, {
      transports: ['console']
    });
    return this.errorHandler.startCatching(options);
  }
  create(options) {
    if (typeof options === 'string') {
      options = {
        logId: options
      };
    }
    return new Logger({
      dependencies: this.dependencies,
      errorHandler: this.errorHandler,
      initializeFn: this.initializeFn,
      isDev: this.isDev,
      transportFactories: this.transportFactories,
      variables: {
        ...this.variables
      },
      ...options
    });
  }
  compareLevels(passLevel, checkLevel, levels = this.levels) {
    const pass = levels.indexOf(passLevel);
    const check = levels.indexOf(checkLevel);
    if (check === -1 || pass === -1) {
      return true;
    }
    return check <= pass;
  }
  initialize(options = {}) {
    this.initializeFn({
      logger: this,
      ...this.dependencies,
      ...options
    });
  }
  logData(data, options = {}) {
    if (this.buffering.enabled) {
      this.buffering.addMessage({
        data,
        date: new Date(),
        ...options
      });
    } else {
      this.processMessage({
        data,
        ...options
      });
    }
  }
  processMessage(message, {
    transports = this.transports
  } = {}) {
    if (message.cmd === 'errorHandler') {
      this.errorHandler.handle(message.error, {
        errorName: message.errorName,
        processType: 'renderer',
        showDialog: Boolean(message.showDialog)
      });
      return;
    }
    let level = message.level;
    if (!this.allowUnknownLevel) {
      level = this.levels.includes(message.level) ? message.level : 'info';
    }
    const normalizedMessage = {
      date: new Date(),
      logId: this.logId,
      ...message,
      level,
      variables: {
        ...this.variables,
        ...message.variables
      }
    };
    for (const [transName, transFn] of this.transportEntries(transports)) {
      if (typeof transFn !== 'function' || transFn.level === false) {
        continue;
      }
      if (!this.compareLevels(transFn.level, message.level)) {
        continue;
      }
      try {
        // eslint-disable-next-line arrow-body-style
        const transformedMsg = this.hooks.reduce((msg, hook) => {
          return msg ? hook(msg, transFn, transName) : msg;
        }, normalizedMessage);
        if (transformedMsg) {
          transFn({
            ...transformedMsg,
            data: [...transformedMsg.data]
          });
        }
      } catch (e) {
        this.processInternalErrorFn(e);
      }
    }
  }
  processInternalErrorFn(_e) {
    // Do nothing by default
  }
  transportEntries(transports = this.transports) {
    const transportArray = Array.isArray(transports) ? transports : Object.entries(transports);
    return transportArray.map(item => {
      switch (typeof item) {
        case 'string':
          return this.transports[item] ? [item, this.transports[item]] : null;
        case 'function':
          return [item.name, item];
        default:
          return Array.isArray(item) ? item : null;
      }
    }).filter(Boolean);
  }
}
var Logger_1 = Logger;

// eslint-disable-next-line no-console
const consoleError = console.error;
class RendererErrorHandler {
  logFn = null;
  onError = null;
  showDialog = false;
  preventDefault = true;
  constructor({
    logFn = null
  } = {}) {
    this.handleError = this.handleError.bind(this);
    this.handleRejection = this.handleRejection.bind(this);
    this.startCatching = this.startCatching.bind(this);
    this.logFn = logFn;
  }
  handle(error, {
    logFn = this.logFn,
    errorName = '',
    onError = this.onError,
    showDialog = this.showDialog
  } = {}) {
    try {
      if (onError?.({
        error,
        errorName,
        processType: 'renderer'
      }) !== false) {
        logFn({
          error,
          errorName,
          showDialog
        });
      }
    } catch {
      consoleError(error);
    }
  }
  setOptions({
    logFn,
    onError,
    preventDefault,
    showDialog
  }) {
    if (typeof logFn === 'function') {
      this.logFn = logFn;
    }
    if (typeof onError === 'function') {
      this.onError = onError;
    }
    if (typeof preventDefault === 'boolean') {
      this.preventDefault = preventDefault;
    }
    if (typeof showDialog === 'boolean') {
      this.showDialog = showDialog;
    }
  }
  startCatching({
    onError,
    showDialog
  } = {}) {
    if (this.isActive) {
      return;
    }
    this.isActive = true;
    this.setOptions({
      onError,
      showDialog
    });
    window.addEventListener('error', event => {
      this.preventDefault && event.preventDefault?.();
      this.handleError(event.error || event);
    });
    window.addEventListener('unhandledrejection', event => {
      this.preventDefault && event.preventDefault?.();
      this.handleRejection(event.reason || event);
    });
  }
  handleError(error) {
    this.handle(error, {
      errorName: 'Unhandled'
    });
  }
  handleRejection(reason) {
    const error = reason instanceof Error ? reason : new Error(JSON.stringify(reason));
    this.handle(error, {
      errorName: 'Unhandled rejection'
    });
  }
}
var RendererErrorHandler_1 = RendererErrorHandler;

var transform_1 = {
  transform: transform$2
};
function transform$2({
  logger,
  message,
  transport,
  initialData = message?.data || [],
  transforms = transport?.transforms
}) {
  return transforms.reduce((data, trans) => {
    if (typeof trans === 'function') {
      return trans({
        data,
        logger,
        message,
        transport
      });
    }
    return data;
  }, initialData);
}

/* eslint-disable no-console */
const {
  transform: transform$1
} = transform_1;
var console_1 = consoleTransportRendererFactory;
const consoleMethods = {
  error: console.error,
  warn: console.warn,
  info: console.info,
  verbose: console.info,
  debug: console.debug,
  silly: console.debug,
  log: console.log
};
function consoleTransportRendererFactory(logger) {
  return Object.assign(transport, {
    format: '{h}:{i}:{s}.{ms}{scope} › {text}',
    transforms: [formatDataFn],
    writeFn({
      message: {
        level,
        data
      }
    }) {
      const consoleLogFn = consoleMethods[level] || consoleMethods.info;

      // make an empty call stack
      setTimeout(() => consoleLogFn(...data));
    }
  });
  function transport(message) {
    transport.writeFn({
      message: {
        ...message,
        data: transform$1({
          logger,
          message,
          transport
        })
      }
    });
  }
}
function formatDataFn({
  data = [],
  logger = {},
  message = {},
  transport = {}
}) {
  if (typeof transport.format === 'function') {
    return transport.format({
      data,
      level: message?.level || 'info',
      logger,
      message,
      transport
    });
  }
  if (typeof transport.format !== 'string') {
    return data;
  }
  data.unshift(transport.format);

  // Concatenate the first two data items to support printf-like templates
  if (typeof data[1] === 'string' && data[1].match(/%[1cdfiOos]/)) {
    data = [`${data[0]}${data[1]}`, ...data.slice(2)];
  }
  const date = message.date || new Date();
  data[0] = data[0].replace(/\{(\w+)}/g, (substring, name) => {
    switch (name) {
      case 'level':
        return message.level;
      case 'logId':
        return message.logId;
      case 'scope':
        {
          const scope = message.scope || logger.scope?.defaultLabel;
          return scope ? ` (${scope})` : '';
        }
      case 'text':
        return '';
      case 'y':
        return date.getFullYear().toString(10);
      case 'm':
        return (date.getMonth() + 1).toString(10).padStart(2, '0');
      case 'd':
        return date.getDate().toString(10).padStart(2, '0');
      case 'h':
        return date.getHours().toString(10).padStart(2, '0');
      case 'i':
        return date.getMinutes().toString(10).padStart(2, '0');
      case 's':
        return date.getSeconds().toString(10).padStart(2, '0');
      case 'ms':
        return date.getMilliseconds().toString(10).padStart(3, '0');
      case 'iso':
        return date.toISOString();
      default:
        return message.variables?.[name] || substring;
    }
  }).trim();
  return data;
}

const {
  transform
} = transform_1;
var ipc = ipcTransportRendererFactory;
const RESTRICTED_TYPES = new Set([Promise, WeakMap, WeakSet]);
function ipcTransportRendererFactory(logger) {
  return Object.assign(transport, {
    depth: 5,
    transforms: [serializeFn]
  });
  function transport(message) {
    if (!window.__electronLog) {
      logger.processMessage({
        data: ['electron-log: logger isn\'t initialized in the main process'],
        level: 'error'
      }, {
        transports: ['console']
      });
      return;
    }
    try {
      const serialized = transform({
        initialData: message,
        logger,
        message,
        transport
      });
      __electronLog.sendToMain(serialized);
    } catch (e) {
      logger.transports.console({
        data: ['electronLog.transports.ipc', e, 'data:', message.data],
        level: 'error'
      });
    }
  }
}

/**
 * Is type primitive, including null and undefined
 * @param {any} value
 * @returns {boolean}
 */
function isPrimitive(value) {
  return Object(value) !== value;
}
function serializeFn({
  data,
  depth,
  seen = new WeakSet(),
  transport = {}
} = {}) {
  const actualDepth = depth || transport.depth || 5;
  if (seen.has(data)) {
    return '[Circular]';
  }
  if (actualDepth < 1) {
    if (isPrimitive(data)) {
      return data;
    }
    if (Array.isArray(data)) {
      return '[Array]';
    }
    return `[${typeof data}]`;
  }
  if (['function', 'symbol'].includes(typeof data)) {
    return data.toString();
  }
  if (isPrimitive(data)) {
    return data;
  }

  // Object types

  if (RESTRICTED_TYPES.has(data.constructor)) {
    return `[${data.constructor.name}]`;
  }
  if (Array.isArray(data)) {
    return data.map(item => serializeFn({
      data: item,
      depth: actualDepth - 1,
      seen
    }));
  }
  if (data instanceof Date) {
    return data.toISOString();
  }
  if (data instanceof Error) {
    return data.stack;
  }
  if (data instanceof Map) {
    return new Map(Array.from(data).map(([key, value]) => [serializeFn({
      data: key,
      depth: actualDepth - 1,
      seen
    }), serializeFn({
      data: value,
      depth: actualDepth - 1,
      seen
    })]));
  }
  if (data instanceof Set) {
    return new Set(Array.from(data).map(val => serializeFn({
      data: val,
      depth: actualDepth - 1,
      seen
    })));
  }
  seen.add(data);
  return Object.fromEntries(Object.entries(data).map(([key, value]) => [key, serializeFn({
    data: value,
    depth: actualDepth - 1,
    seen
  })]));
}

(function (module) {

	const Logger = Logger_1;
	const RendererErrorHandler = RendererErrorHandler_1;
	const transportConsole = console_1;
	const transportIpc = ipc;
	if (typeof process === 'object' && process.type === 'browser') {
	  // eslint-disable-next-line no-console
	  console.warn('electron-log/renderer is loaded in the main process. ' + 'It could cause unexpected behaviour.');
	}
	module.exports = createLogger();
	module.exports.Logger = Logger;
	module.exports.default = module.exports;
	function createLogger() {
	  const logger = new Logger({
	    allowUnknownLevel: true,
	    errorHandler: new RendererErrorHandler(),
	    initializeFn: () => {},
	    logId: 'default',
	    transportFactories: {
	      console: transportConsole,
	      ipc: transportIpc
	    },
	    variables: {
	      processType: 'renderer'
	    }
	  });
	  logger.errorHandler.setOptions({
	    logFn({
	      error,
	      errorName,
	      showDialog
	    }) {
	      logger.transports.console({
	        data: [errorName, error].filter(Boolean),
	        level: 'error'
	      });
	      logger.transports.ipc({
	        cmd: 'errorHandler',
	        error: {
	          cause: error?.cause,
	          code: error?.code,
	          name: error?.name,
	          message: error?.message,
	          stack: error?.stack
	        },
	        errorName,
	        logId: logger.logId,
	        showDialog
	      });
	    }
	  });
	  if (typeof window === 'object') {
	    window.addEventListener('message', event => {
	      const {
	        cmd,
	        logId,
	        ...message
	      } = event.data || {};
	      const instance = Logger.getInstance({
	        logId
	      });
	      if (cmd === 'message') {
	        instance.processMessage(message, {
	          transports: ['console']
	        });
	      }
	    });
	  }

	  // To support custom levels
	  return new Proxy(logger, {
	    get(target, prop) {
	      if (typeof target[prop] !== 'undefined') {
	        return target[prop];
	      }
	      return (...data) => logger.logData(data, {
	        level: prop
	      });
	    }
	  });
	} 
} (renderer$1));

var rendererExports = renderer$1.exports;

const renderer = rendererExports;
var renderer_1 = renderer;

var log = /*@__PURE__*/getDefaultExportFromCjs(renderer_1);

// Maps webContentsId → server hostname (for context lookup)

// Define the log context interface

/**
 * Get process context information
 */
const getProcessContext = () => {
  if (typeof process === 'undefined') return 'unknown';
  if (process.type === 'browser') {
    return 'main';
  }
  if (process.type === 'renderer') {
    // Try to detect renderer type based on environment
    if (typeof window !== 'undefined') {
      var _window$location, _window$location2, _window$location3;
      // Check if this is the root window
      if (((_window$location = window.location) === null || _window$location === undefined ? undefined : _window$location.pathname) === '/index.html' || ((_window$location2 = window.location) === null || _window$location2 === undefined ? undefined : _window$location2.pathname) === '/') {
        return 'renderer:root';
      }

      // Check if this is the video call window
      if (((_window$location3 = window.location) === null || _window$location3 === undefined ? undefined : _window$location3.pathname) === '/video-call-window.html') {
        return 'renderer:videocall';
      }

      // Default to webview for other renderer processes
      return 'renderer:webview';
    }
    return 'renderer:unknown';
  }
  return 'preload';
};

/**
 * Get component context based on the calling code location
 */
// eslint-disable-next-line complexity
const getComponentContext = (captureStack = false) => {
  if (!captureStack) {
    return 'general';
  }
  const error = new Error();
  const stack = error.stack || '';

  // Analyze stack trace to determine component context (privacy-safe)
  if (stack.includes('auth') || stack.includes('login') || stack.includes('Login')) {
    return 'auth';
  }
  if (stack.includes('connection') || stack.includes('websocket') || stack.includes('network')) {
    return 'connection';
  }
  if (stack.includes('notification') || stack.includes('Notification')) {
    return 'notifications';
  }
  if (stack.includes('update') || stack.includes('Update')) {
    return 'updates';
  }
  if (stack.includes('outlook') || stack.includes('Outlook') || stack.includes('outlookCalendar') || stack.includes('getOutlookEvents') || stack.includes('syncEventsWithRocketChatServer')) {
    return 'outlook';
  }
  if (stack.includes('server') || stack.includes('Server') || stack.includes('servers')) {
    return 'servers';
  }
  if (stack.includes('video') || stack.includes('Video') || stack.includes('jitsi')) {
    return 'videocall';
  }
  if (stack.includes('preload')) {
    return 'preload';
  }
  if (stack.includes('ipc') || stack.includes('IPC')) {
    return 'ipc';
  }
  if (stack.includes('storage') || stack.includes('Storage') || stack.includes('store')) {
    return 'storage';
  }
  if (stack.includes('ui') || stack.includes('UI') || stack.includes('component')) {
    return 'ui';
  }
  if (stack.includes('app') || stack.includes('App') || stack.includes('main')) {
    return 'app';
  }
  return 'general';
};

// Function to override console methods in renderer processes with enhanced context
try {
  // Get process context once
  const processContext = getProcessContext();

  // For webviews, try to get server index from main process
  let serverTag = '';
  if (processContext === 'renderer:webview' && typeof window !== 'undefined') {
    try {
      var _window$location;
      const result = electron.ipcRenderer.sendSync('log-viewer-window/get-server-tag', ((_window$location = window.location) === null || _window$location === void 0 ? void 0 : _window$location.origin) || '');
      if (result) {
        serverTag = ` [${result}]`;
      }
    } catch {
      // Silently fail if IPC not available
    }
  }
  if (typeof console !== 'undefined') {
    // Store original console methods
    const originalConsole = {
      log: console.log,
      info: console.info,
      warn: console.warn,
      error: console.error,
      debug: console.debug
    };

    // Override console.log to use electron-log debug level with context
    console.log = (...args) => {
      try {
        const component = getComponentContext();
        const contextStr = `[${processContext}]${serverTag}${component !== 'general' ? ` [${component}]` : ''}`;
        log.debug(contextStr, ...args);
      } catch {
        originalConsole.log(...args);
      }
    };

    // Override console.info to use electron-log info level with context
    console.info = (...args) => {
      try {
        const component = getComponentContext();
        const contextStr = `[${processContext}]${serverTag}${component !== 'general' ? ` [${component}]` : ''}`;
        log.info(contextStr, ...args);
      } catch {
        originalConsole.info(...args);
      }
    };

    // Override console.warn to use electron-log warn level with context
    console.warn = (...args) => {
      try {
        const component = getComponentContext(true);
        const contextStr = `[${processContext}]${serverTag}${component !== 'general' ? ` [${component}]` : ''}`;
        log.warn(contextStr, ...args);
      } catch {
        originalConsole.warn(...args);
      }
    };

    // Override console.error to use electron-log error level with context
    console.error = (...args) => {
      try {
        const component = getComponentContext(true);
        const contextStr = `[${processContext}]${serverTag}${component !== 'general' ? ` [${component}]` : ''}`;
        log.error(contextStr, ...args);
      } catch {
        originalConsole.error(...args);
      }
    };

    // Override console.debug to use electron-log debug level with context
    console.debug = (...args) => {
      try {
        const component = getComponentContext();
        const contextStr = `[${processContext}]${serverTag}${component !== 'general' ? ` [${component}]` : ''}`;
        log.debug(contextStr, ...args);
      } catch {
        originalConsole.debug(...args);
      }
    };

    // Add marker to know console override is active
    console.original = originalConsole;
  }
} catch (error) {
  // Silently fail if electron-log isn't available in this context
}

console.log('[Rocket.Chat Desktop] Preload.ts');
electron.contextBridge.exposeInMainWorld('JitsiMeetElectron', JitsiMeetElectron);
electron.contextBridge.exposeInMainWorld('RocketChatDesktop', RocketChatDesktop);
let retryCount = 0;
let startInProgress = false;
const start = async () => {
  if (startInProgress) {
    return;
  }
  startInProgress = true;
  console.log('[Rocket.Chat Desktop] Preload.ts start fired');
  const serverUrl = await invoke('server-view/get-url');
  if (retryCount > 5) {
    startInProgress = false;
    return;
  }
  if (!serverUrl) {
    console.log('[Rocket.Chat Desktop] serverUrl is not defined');
    console.log('[Rocket.Chat Desktop] Preload start - retrying in 1 seconds');
    startInProgress = false;
    setTimeout(start, 1000);
    retryCount += 1;
    return;
  }
  window.removeEventListener('load', start);
  setServerUrl(serverUrl);
  await whenReady();
  await createRendererReduxStore();
  await invoke('server-view/ready');
  console.log('[Rocket.Chat Desktop] waiting for RocketChatDesktop.onReady');
  RocketChatDesktop.onReady(() => {
    console.log('[Rocket.Chat Desktop] RocketChatDesktop.onReady fired');
    listen(WEBVIEW_DID_NAVIGATE, debounce(() => {
      const resources = electron.webFrame.getResourceUsage();
      // TODO: make this configurable
      if (resources.images.size > 50 * 1024 * 1024) {
        electron.webFrame.clearCache();
      }
    }, 1000 * 30));
    listenToNotificationsRequests();
    listenToScreenSharingRequests();
    listenToMessageBoxEvents();
    handleTrafficLightsSpacing();
  });
};
console.log('[Rocket.Chat Desktop] waiting for window load');
window.addEventListener('load', start);
window.addEventListener('DOMContentLoaded', start);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,[encoded data, 362464 characters]
