"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var guest_exports = {};
__export(guest_exports, {
  CMicroAppGuest: () => CMicroAppGuest
});
module.exports = __toCommonJS(guest_exports);
var import_lodash = __toESM(require("lodash"));
var import_uuid = require("uuid");
var import_pui_theme = require("@elliemae/pui-theme");
var import_ssf_guest = require("@elliemae/ssf-guest");
var import_pui_analytics_so = require("@elliemae/pui-analytics-so");
var import_window = require("../window.js");
var import_app_config = require("../app-config/index.js");
var import_config = require("../app-config/config.js");
var import_history2 = require("../history.js");
var import_console_logger = require("../console-logger.js");
var import_logger = require("../logger.js");
var import_web_storage = require("../web-storage.js");
var import_logrocket = require("../logrocket.js");
var import_app_bridge = require("./app-bridge.js");
var import_helpers = require("../helpers.js");
var import_ssf_host2 = require("./ssf-host.js");
const isCrossDomain = () => {
  try {
    window.parent.document;
    return false;
  } catch (ex) {
    return true;
  }
};
var CommunicationMethod = /* @__PURE__ */ ((CommunicationMethod2) => {
  CommunicationMethod2["SSF"] = "ssf";
  CommunicationMethod2["APPSDK"] = "app-sdk";
  return CommunicationMethod2;
})(CommunicationMethod || {});
class CMicroAppGuest {
  /**
   * unique microapp id
   */
  #uuid;
  static instance;
  logger;
  /**
   * LogRocket instance
   */
  #logRocket;
  appId;
  props;
  containerId;
  /**
   * communication method used between microapps
   */
  #communicationMethod;
  /**
   * reference to SSFHost instance
   */
  #ssfHostRef;
  /**
   * true if the app prefers to use SSF V2 Guest from App SDK to communicate with host(optional, default: true)
   */
  #useV2Guest;
  /**
   * AppBridge instance
   */
  #appBridge = null;
  onInit;
  onMount;
  onUnmount;
  onGetRef;
  // eslint-disable-next-line max-statements
  constructor(params) {
    this.containerId = "app-container";
    window.emui.uuid = window.emui.uuid || (0, import_uuid.v4)();
    this.appId = window.emui?.appId || (0, import_config.getAppConfigValue)("appId");
    this.#uuid = window.emui.uuid;
    this.#communicationMethod = "app-sdk" /* APPSDK */;
    this.props = {
      host: null,
      hostUrl: null,
      prevState: null,
      history: params?.history || import_history2.browserHistory,
      theme: (0, import_pui_theme.getDefaultTheme)(),
      manifestPath: "./latest"
    };
    this.logger = params?.logger || import_console_logger.consoleLogger;
    (0, import_logger.setLogger)(this.logger);
    this.#logRocket = params?.logRocket ?? window.emui?.logRocket;
    (0, import_logrocket.setLogRocket)(this.#logRocket);
    if (params?.ssfHostRef) (0, import_ssf_host2.setSSFHost)(params.ssfHostRef);
    this.#ssfHostRef = (0, import_ssf_host2.getSSFHost)();
    this.#useV2Guest = params?.useV2Guest !== false;
    this.onInit = params?.onInit;
    this.onMount = params?.onMount;
    this.onUnmount = params?.onUnmount;
    this.onGetRef = params?.onGetRef;
    this.getHost = this.getHost.bind(this);
    this.getLogger = this.getLogger.bind(this);
    this.getProps = this.getProps.bind(this);
    this.#addAppToGlobalVariable();
  }
  static getInstance(params) {
    if (!this.instance) {
      this.instance = new CMicroAppGuest(params);
    }
    return this.instance;
  }
  static isInitialized() {
    return !!this.instance;
  }
  static isHosted() {
    return !!this.instance?.props?.host;
  }
  getHost() {
    return this.props.host;
  }
  getLogger() {
    return this.logger;
  }
  getObject(objectId) {
    let host = null;
    if (this.#communicationMethod === "ssf" /* SSF */) {
      host = this.getHost();
      return host.getObject(objectId);
    }
    host = this.getHost();
    if (!host) return Promise.resolve(null);
    return host.getObject(objectId);
  }
  /**
   * subscribe to the scripting object event
   * @param {SubscribeParam<EventId, AppEvents[EventId]>} params - the parameters for the subscription
   * @param {string} params.soName - the name of the scripting object
   * @param {string} params.eventName - the name of the event
   * @param {Function} params.callback - the callback function to be called when the event is triggered
   * @returns {void}
   */
  subscribe(params) {
    let host = null;
    if (this.#communicationMethod === "ssf" /* SSF */) {
      host = this.getHost();
      return host.subscribe(params);
    }
    host = this.getHost();
    return host.subscribe(params);
  }
  /**
   * unsubscribe from the scripting object event
   * @param params - parameters for the unsubscription
   */
  unsubscribe(params) {
    let host = null;
    if (this.#communicationMethod === "ssf" /* SSF */) {
      host = this.getHost();
      host.unsubscribe(params);
    }
    host = this.getHost();
    host.unsubscribe(params);
  }
  getProps() {
    return this.props;
  }
  /**
   * add the microapp to the global variable in the parent window and current window
   */
  #addAppToGlobalVariable() {
    const browserWindow = (0, import_window.getWindow)();
    if (!browserWindow) return;
    browserWindow.emui = browserWindow.emui || {};
    const app = {
      uuid: this.#uuid,
      init: this.init.bind(this),
      mount: this.mount.bind(this),
      unmount: this.unmount.bind(this),
      getRef: this.getRef.bind(this),
      navigate: this.navigate.bind(this)
    };
    if (browserWindow.emui[this.appId]) {
      if (Array.isArray(browserWindow.emui[this.appId])) {
        const existingApps = browserWindow.emui[this.appId];
        const appIndex = existingApps.findIndex((a) => a.uuid === this.#uuid);
        if (appIndex > -1) existingApps[appIndex] = app;
        else existingApps.push(app);
      } else if (browserWindow.emui[this.appId].uuid === this.#uuid) {
        browserWindow.emui[this.appId] = app;
      } else if (typeof browserWindow.emui[this.appId].init === "undefined") {
        browserWindow.emui[this.appId] = {
          ...browserWindow.emui[this.appId],
          ...app
        };
      } else {
        browserWindow.emui[this.appId] = [
          browserWindow.emui[this.appId],
          app
        ];
      }
    } else {
      browserWindow.emui[this.appId] = app;
    }
    window.emui.app = app;
    window.addEventListener("beforeunload", this.#onWindowUnload.bind(this));
  }
  /**
   * remove the microapp from the global variable from the parent window and current window
   */
  #onWindowUnload() {
    const browserWindow = (0, import_window.getWindow)();
    if (Array.isArray(browserWindow.emui[this.appId])) {
      const existingApps = browserWindow.emui[this.appId];
      const index = existingApps.findIndex((app) => app.uuid === this.#uuid);
      if (index > -1) existingApps.splice(index, 1);
      if (existingApps.length === 0) {
        delete browserWindow.emui[this.appId];
      }
    } else {
      delete browserWindow.emui[this.appId];
    }
    delete window.emui.app;
    this.unmount({ containerId: this.containerId }).catch(() => {
    });
  }
  getSessionStorageItem(key) {
    let value = sessionStorage.getItem(key);
    const host = this.getHost();
    if (!value && host?.getItem) {
      value = host.getItem(key);
    }
    return value;
  }
  async findHost() {
    let host = null;
    if (!isCrossDomain()) {
      host = window.parent?.emui?.MicroAppHost ?? null;
    }
    if (!host && this.#useV2Guest) {
      host = new import_ssf_guest.SSFGuest({ appLogger: this.logger });
      if (await (0, import_helpers.abortPromise)({
        promise: host.connect(),
        delay: 1e3,
        retValue: false
      })) {
        host = null;
      } else this.#communicationMethod = "ssf" /* SSF */;
    }
    return host;
  }
  get uuid() {
    return this.#uuid;
  }
  async init(options) {
    const { history, ...rest } = options ?? {};
    this.props = import_lodash.default.merge(this.props, rest);
    if (!this.props.host) {
      const host = await this.findHost();
      if (host) {
        this.props.host = host;
      } else this.logger.warn("unable to connect to host microapp");
    }
    __webpack_public_path__ = __webpack_public_path__.replace(/\/?$/, "/");
    return (0, import_app_config.loadAppConfig)().then(() => {
      const instanceId = this.getSessionStorageItem("instanceId") || "";
      const userId = this.getSessionStorageItem("userId") || "";
      (0, import_pui_analytics_so.updateBAEventParameters)({ appId: this.appId, instanceId, userId });
      const useParentHistory = (0, import_config.getAppConfigValue)("useParentHistory", true);
      if (useParentHistory && history) {
        this.props.history = history;
      }
      if (!useParentHistory && options?.initialRoute) {
        this.props.history.push(options.initialRoute);
      }
      return (0, import_app_bridge.getAppBridge)().then((appBridge) => {
        this.#appBridge = appBridge;
        if (this.onInit) this.onInit(this.props);
      });
    });
  }
  mount(options = { containerId: "app-container" }) {
    this.containerId = options?.containerId;
    return Promise.resolve().then(() => {
      if (this.onMount) this.onMount(options);
    });
  }
  unmount(options) {
    (0, import_web_storage.removeStorageEvents)();
    return Promise.resolve().then(
      () => this.onUnmount ? this.onUnmount(options) : null
    );
  }
  getRef() {
    return this.onGetRef ? this.onGetRef() : null;
  }
  navigate(url, state) {
    if (url) this.props.history.push(url, state);
  }
  /**
   * add scripting object for child microapp to use
   * @param so - The scripting object to be added.
   * @param params - Optional parameters for adding the scripting object.
   */
  addScriptingObject(so, params) {
    if (this.#appBridge) {
      this.#appBridge.addScriptingObject(so, params);
    }
    this.#ssfHostRef.addScriptingObject(so, params);
  }
  /**
   * Dispatches an event to the child microapp.
   * @param {DispatchEventParam<EventId, Params, Options>} params - Event parameters.
   * @returns {Promise<any[]>} A promise that resolves with the combined results of dispatched events.
   */
  async dispatchEvent(params) {
    if (this.#appBridge) {
      const [appBridgeResult, ssfResult] = await Promise.all([
        this.#appBridge.dispatchEvent(params),
        this.#ssfHostRef.dispatchEvent(params)
      ]);
      if (Array.isArray(appBridgeResult) && Array.isArray(ssfResult)) {
        return appBridgeResult.concat(ssfResult);
      }
      return Promise.resolve();
    }
    return this.#ssfHostRef.dispatchEvent(params);
  }
  /**
   * removes scripting object from child microapp use
   * @param objectId unique id of the scripting object
   */
  removeScriptingObject(objectId) {
    if (this.#appBridge) {
      this.#appBridge.removeScriptingObject(objectId);
    }
    this.#ssfHostRef.removeScriptingObject(objectId);
  }
}
