/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import * as l from "@esri/solution-common";
import { request as p, getWorkflowBaseURL as d, getWorkflowManagerAuthorized as g } from "@esri/solution-common";
import c from "@arcgis/core/identity/IdentityManager.js";
import _ from "@arcgis/core/identity/OAuthInfo.js";
import U from "@arcgis/core/portal/Portal.js";
import { p as f, a as S, r as m } from "./helpers.js";
import { E as h, g as u } from "./interfaces.js";
async function I(i, e, t) {
  let r = t;
  return i && (i?.IsEnterprisePortal && await w(
    "",
    // the portal url
    e
  ) && r.push(h.NOTEBOOK), await f(e) ? t.push(h.VELOCITY) : i?.PortalUserPrivileges && [
    u.VELOCITYFEEDS,
    u.VELOCITYBIGDATA,
    u.VELOCITYREALTIME
  ].forEach((n) => {
    const a = t.indexOf(n) || -1;
    a !== -1 && t.splice(a, 1);
  }), r = r.concat(
    b(
      A(i),
      O(i)
    )
  ), r = r.concat(v(i)), r = r.concat(await P(i))), Promise.resolve(r);
}
function b(i, e) {
  let t = [];
  return i && e ? t = [
    h.TRACKINGADMINANDTRACKING,
    h.TRACKINGADMIN,
    h.TRACKING
  ] : i && !e ? t = [h.TRACKINGADMIN] : !i && e && (t = [h.TRACKING]), t;
}
function v(i) {
  return R(
    i
  ) ? [h.HUBPREMIUM] : [];
}
async function P(i) {
  const e = i?.RestUserSession;
  if (!e?.username)
    return [];
  const t = await d(e);
  return await g(t, e) ? [h.WORKFLOW] : [];
}
async function w(i, e) {
  const t = i + "/sharing/rest", r = {
    authentication: e,
    portal: t,
    params: {
      f: "json"
    }
  };
  return p(`${t}/portals/self/servers`, r).then((s) => s?.servers?.find((o) => o.serverFunction.indexOf("NotebookServer") > -1), (s) => (console.error(s), !1));
}
function A(i) {
  const e = i?.PortalUserSubset?.privileges, t = [
    "portal:admin:create",
    "portal:admin:delete",
    "portal:admin:update",
    "portal:admin:reassign"
  ];
  return e ? t.every(
    (r) => e.some((s) => s.startsWith(r))
  ) : !1;
}
function O(i) {
  return i?.PortalSubset?.locationTrackingEnabled || !1;
}
function R(i) {
  return i?.PortalSubset?.hubPremiumEnabled || !1;
}
class T {
  constructor(e, t, r, s) {
    this._credential = void 0, this._isEnterprise = !1, this._locale = "en", this._portalSubset = void 0, this._portalUserSubset = void 0, this._portalUserEnrichedPrivileges = void 0, this._arcGISOnlineReachable = !0, this._searchArcGISOnlineEnabled = !0, this._signInParam = void 0, this._clientId = e ?? "", this._locale = r ?? "en", this._portalUrl = t ?? "https://www.arcgis.com", this._portalRestUrl = this._portalUrl + "/sharing/rest", this._portalUrl = location.origin.endsWith(".arcgis.com") ? window.location.origin : this._portalUrl, this._signInParam = s;
    const o = new _({
      appId: this._clientId,
      locale: this._locale,
      popup: !1,
      // inline redirects don't require any additional app configuration
      portalUrl: this._portalUrl,
      preserveUrlHash: !0
    });
    try {
      c.registerOAuthInfos([o]);
    } catch (n) {
      console.log(n);
    }
    this._portal = new U({ url: this._portalUrl });
  }
  get Credential() {
    return this._credential;
  }
  get IsEnterprisePortal() {
    return this._isEnterprise;
  }
  get IsSignedIn() {
    return !!this._credential;
  }
  get Portal() {
    return this._portal;
  }
  get PortalSubset() {
    return this._portalSubset;
  }
  get PortalUrl() {
    return this._portalUrl;
  }
  get PortalUserOrg() {
    return this._portalSubset && this._portalSubset.id;
  }
  get PortalUserName() {
    return this._portalUserSubset && this._portalUserSubset.username || "";
  }
  get PortalUserSubset() {
    return this._portalUserSubset;
  }
  get PortalUserPrivileges() {
    let e = [];
    return this._portalUserSubset?.privileges && (e = this._portalUserSubset.privileges), e;
  }
  /**
   * Enriched user privileges, pre-computed once at sign-in.
   *
   * Includes the base portal privileges plus custom solution-specific
   * privileges (Velocity, Notebook Server, Hub Premium, Location Tracking,
   * Workflow Manager) that would otherwise require additional network
   * requests each time a solution details page is opened. Falls back to
   * the base portal privileges if enrichment hasn't completed yet (e.g.,
   * during sign-in or for anonymous sessions).
   */
  get PortalUserEnrichedPrivileges() {
    return this._portalUserEnrichedPrivileges ?? this.PortalUserPrivileges;
  }
  get SignInParam() {
    return this._signInParam;
  }
  get CanDeleteSolution() {
    return this.PortalUserPrivileges.includes("portal:admin:deleteItems");
  }
  get CanUpdateSolution() {
    return this.PortalUserPrivileges.includes("portal:admin:updateItems");
  }
  get CanUseAI() {
    const e = this._portalSubset?.orgSettings, t = this.PortalUserPrivileges.includes("portal:user:useAIAssistants");
    return e?.aiAssistantsEnabled ? e.aiAssistantsEnabled && !e.blockBetaApps && t : !1;
  }
  get CanViewOrg() {
    return this.PortalUserPrivileges.includes("portal:admin:viewItems");
  }
  get CanSearchArcGISOnline() {
    return this._searchArcGISOnlineEnabled && this._arcGISOnlineReachable;
  }
  /** Checks if the ArcGIS Online group is reachable for Enterprise portals. */
  async checkArcGISOnlineReachability(e) {
    if (this._isEnterprise && this._searchArcGISOnlineEnabled && e) {
      const r = `${S(this._portalUrl)}/sharing/rest`, s = new l.UserSession({});
      try {
        await l.searchItems({
          q: `group:${e} type:Solution`,
          num: 1,
          start: 1,
          authentication: s,
          portal: r
        }), this._arcGISOnlineReachable = !0;
      } catch (o) {
        this._arcGISOnlineReachable = !1, console.warn("ArcGIS Online solutions group not reachable:", o);
      }
    }
  }
  get RestUserSession() {
    const e = c.findServerInfo(this._portalRestUrl), t = this._credential ? l.UserSession.fromCredential(this._credential, e) : this._isEnterprise ? new l.UserSession({}) : new l.UserSession({ portal: this._portalRestUrl });
    return t.portal = this.PortalSubset?.restUrl ? this.PortalSubset?.restUrl : t.portal, t.clientId = this._credential?._oAuthCred?.appId, t._refreshToken = this._credential?._oAuthCred?.refreshToken, t;
  }
  /**
   * Initializes the Auth object. This method must be called before any other Auth methods.
   * If the user is not authorized to use the app, the page will be redirected to an error page.
   *
   * @returns Promise that resolves with the initialized Auth object
   */
  async initialize(e = !1, t) {
    try {
      await this._init(e, t);
    } catch {
      this.destroy();
    }
    return this;
  }
  destroy() {
    this._credential = void 0, this._portalSubset = void 0, this._portalUserSubset = void 0, c.destroyCredentials();
  }
  /**
   * Signs into app and refreshes the window.location or switches to the supplied URL.
   *
   * @param signInParamValue If supplied, the parameter `signInParam` with the supplied value
   * will be added to the redirect uri's search params
   */
  async signIn(e = "") {
    c.setOAuthRedirectionHandler((t) => {
      const r = t.authorizeParams.redirect_uri;
      if (e.length > 0) {
        const s = r.split("?"), o = s[0];
        let n = "";
        const a = new URLSearchParams(s[1] || "");
        a.append("signInParam", e), n = "?" + a.toString(), t.authorizeParams.redirect_uri = o + n;
      }
      window.location.href = t.authorizeUrl + "?" + this._objectToQuery(t.authorizeParams);
    }), await c.getCredential((this._portalSubset?.portalUrl ?? this._portalUrl) + "/sharing").then(
      (t) => {
        t && window.location.reload();
      }
    );
  }
  /**
   * Signs out of app.
   * When the user is...
   *  on the solutions page they should stay on that page
   *  on a solutions details page they should stay on that page
   *  on the deployments page they should stay on that page
   *  on a deployed solutions page they should be sent to the deployments page
   *  on the resources page they should stay on that page
   */
  signOut() {
    const e = window.location.href, t = /[\/]\b([0-9A-Fa-f]){32}\b/g;
    let r = e.match(t) ? e.replace(t, "") : e;
    r = m(r, "sortField", "suggested");
    const o = `${this._portal?.restUrl ?? this._portalUrl + "/sharing/rest"}/oauth2/signout?client_id=${this._clientId}&redirect_uri=${encodeURIComponent(r)}`;
    this.destroy(), window.location.replace(o);
  }
  /**
   * Refreshes the user session token
   */
  refreshSession() {
    const e = this.RestUserSession;
    if (!(!e || !this.IsSignedIn))
      return e.exchangeRefreshToken();
  }
  // ---------------------------------------------------------------------------------------------------------------- //
  /**
   * Generates the organization URL.
   * @param portalUrl The URL to the portal instance.
   * @param portalUrlKey The prefix selected by the organization's administrator to be used with the customBaseURL.
   * @param portalCustomBaseUrl The custom base URL for the portal.
   * @returns
   */
  _getOrgUrl(e, t, r) {
    return t && r ? window.location.protocol + "//" + t.toLowerCase() + "." + r : e;
  }
  /**
   * Initializes the Auth object. This method must be called before any other Auth methods.
   * If the user is not authorized to use the app, the page will be redirected to an error page.
   * @returns Promise that resolves with the initialized Auth object
   */
  async _init(e = !1, t) {
    try {
      this._credential = await c.checkSignInStatus(this._portalUrl + "/sharing");
    } catch (s) {
      console.log(s);
    }
    try {
      const s = await c.checkAppAccess(this._portalUrl + "/sharing", this._clientId);
      (typeof s.valid < "u" && !s.valid || s.viewOnlyUserTypeApp) && window.location.replace(`error.html?error=blocked&locale=${this._locale}`), this._credential = s.credential;
    } catch (s) {
      s.name;
    }
    this._searchArcGISOnlineEnabled = await this._checkSearchArcGISOnlineEnabled(e, this._portal.restUrl), this._portal.authMode = e ? "immediate" : "auto", await this._portal.load();
    const r = this._credential ? await l.getOrganizationSettings(this.RestUserSession) : {};
    if (this._isEnterprise = this._portal.isPortal, await this.checkArcGISOnlineReachability(t), this._portalSubset = {
      name: this._portal.name ?? "",
      id: this._portal.id ?? "",
      restUrl: this._portal.restUrl ?? "",
      portalUrl: this._portal.url ?? "",
      urlKey: this._portal.urlKey ?? "",
      hostName: this._portal.portalHostname ?? "",
      orgUrl: this._getOrgUrl(this._portal.url, this._portal.urlKey ?? "", this._portal.customBaseUrl ?? ""),
      locationTrackingEnabled: this._portal.helperServices.hasOwnProperty("locationTracking"),
      hubPremiumEnabled: this._portal.portalProperties?.hub?.enabled || !1,
      workflowURL: this._portal.helperServices?.workflowManager?.url ?? this._portal.url,
      isReadOnly: this._portal.isReadOnly,
      orgSettings: r
    }, this._portalUserSubset = {
      fullName: this._portal.user?.fullName ?? "",
      username: this._portal.user?.username ?? "",
      culture: this._portal.user?.culture?.toLowerCase() || "en",
      thumbnailUrl: this._portal.user?.thumbnailUrl || this._portal.url + "/home/js/arcgisonline/css/images/no-user-thumb.jpg",
      orgId: this._portal.user?.orgId ?? "",
      privileges: this._portal.user.privileges,
      role: this._portal.user?.role ?? "",
      roleId: this._portal.user?.roleId ?? void 0
    }, this._isEnterprise && this._portalSubset && (this._portalSubset.workflowURL = await l.getWorkflowEnterpriseServerRootURL(
      this._portal.restUrl,
      this.RestUserSession || new l.UserSession({})
    )), this._portal?.user?.roleId && this._portalUserSubset && (this._portalUserSubset.roleId = this._portal.user.roleId), this._credential && this._portalUserSubset)
      try {
        this._portalUserEnrichedPrivileges = await I(
          this,
          this.RestUserSession,
          [...this._portalUserSubset.privileges]
        );
      } catch (s) {
        console.warn("Failed to enrich user privileges during sign-in:", s), this._portalUserEnrichedPrivileges = [...this._portalUserSubset.privileges];
      }
    return this;
  }
  async _checkSearchArcGISOnlineEnabled(e, t) {
    if (e)
      try {
        const r = `${t}/portals/self/settings`, s = await l.request(r, {
          authentication: this._credential ? this.RestUserSession : void 0
        });
        return s?.portalConfigProperties?.searchArcGISOnlineEnabled !== void 0 ? s.portalConfigProperties.searchArcGISOnlineEnabled : !1;
      } catch (r) {
        return console.warn("Failed to fetch portal settings:", r), !1;
      }
    else
      return !0;
  }
  /**
   * Checks if an object is serializable.
   * @param obj Object to check
   * This function checks if the object has a `toJSON` method, which is a
   * @returns Boolean indicating whether the object is serializable.
   */
  _isSerializable(e) {
    return e && typeof e == "object" && "toJSON" in e && typeof e.toJSON == "function";
  }
  /**
   * Converts a hashmap of query parameters to a query string. Following formatting rules applies:
   *   - object values that implements `toJSON()` are stringified
   *   - array value will map to multiple key value pairs. ie `{ key: ["v1", "v2"] }` returns `key=v1&key=v2
   *
   * @param queryParameters the query parameters to convert to a string
   * @param replacers optional replacer functions defined per key
   *
   * @example
   * const queryParameters = {
   *   objectIds: [1, 2, 3, 4]
   * };
   *
   * // returns: "objectIds=1&objectIds=2&objectIds=3&objectIds=4"
   * objectToQuery(queryParameters);
   *
   * // returns: "objectIds=1,2,3,4"
   * objectToQuery(queryParameters, {
   *   objectIds: (v) => v.join(",")
   * });
   *
   * // returns: "objectIds=1,2,3,4"
   * objectToQuery(queryParameters, (k, v) => {
   *   switch (k) {
   *     case "objectIds":
   *       return v.join(","));
   *     default:
   *       return "" + v;
   *   }
   * });
   *
   * Copied from function exported in arcgis-js-api but not added to JSAPI.
   */
  _objectToQuery(e, t) {
    return e ? t && typeof t == "function" ? Object.keys(e).map((r) => encodeURIComponent(r) + "=" + encodeURIComponent(t(r, e[r]))).join("&") : Object.keys(e).map((r) => {
      const s = e[r];
      if (s == null)
        return "";
      const o = encodeURIComponent(r) + "=", n = t && t[r];
      return n ? o + encodeURIComponent(n(s)) : Array.isArray(s) ? s.map((a) => this._isSerializable(a) ? o + encodeURIComponent(JSON.stringify(a)) : o + encodeURIComponent(a)).join("&") : this._isSerializable(s) ? o + encodeURIComponent(JSON.stringify(s)) : o + encodeURIComponent(s);
    }).filter((r) => r).join("&") : "";
  }
}
export {
  T as A
};
