// Copyright (c) 2009-2026 SAP SE, All Rights Reserved
/**
 * @fileoverview This module is the root of the SAP Business Client enablement.
 */

sap.ui.define([
    // sap.ushell.base is a bootstrap dependency!
    // Be careful when adding new dependencies
    "sap/base/Log",
    "sap/base/util/ObjectPath",
    "sap/ushell/base/requireAsync"
], (
    Log,
    ObjectPath,
    requireAsync
) => {
    "use strict";

    const oEPCMNavigationMode = {
        embedded: 0,
        newWindowThenEmbedded: 1,
        newWindow: 1,
        replace: 0
    };

    class SAPBusinessClientEnablement {
        /**
         * Exposes a private "epcm" object used for the NWBC for Desktop integration.
         *
         * @returns {object} A native browser object.
         * @private
         */
        getPrivateEpcm () {
            if (typeof window.external?.getPrivateEpcm === "function") {
                return window.external.getPrivateEpcm();
            }
        }

        /**
         * Determine the shell type considering NWBC
         * Version 6.0+ client case.
         *
         * @returns {string}
         *   the shell type ("NWBC" or "FLP"), based on whether NWBC v6.0+
         *   Client is detected.
         */
        getShellType () {
            return this.#isFeatureBitEnabled(1) ? "NWBC" : "FLP";
        }

        /**
         * Detects whether NWBC can logout natively.
         *
         * NWBC exposes a feature bit vector via the "getNwbcFeatureBits" method of the private "epcm" object.
         * This is expected to be a string in hex format representing 4 bits,
         * where the second least significant bit represents native logout capability.
         *
         * For example: "B" = 1011, second last bit is 1, therefore native logout capability is enabled.
         *
         * @returns {boolean} Whether the browser can logout natively.
         */
        hasNativeLogoutCapability () {
            return this.#isFeatureBitEnabled(2);
        }

        doLogout (sLogOffUrl) {
            const oLogOffUrl = new URL(sLogOffUrl, this.getLocationHref());
            oLogOffUrl.search = "";
            const sFullLogOffUrl = oLogOffUrl.toString();
            this.getPrivateEpcm().doLogOff(sFullLogOffUrl);
        }

        /**
         * Detects whether the browser can open WebGui applications natively.
         *
         * This is expected to happen from NWBC Version 6 onwards.
         *
         * NWBC exposes a feature bit vector via the "getNwbcFeatureBits" method of the private "epcm" object.
         * This is expected to be a string in hex format representing 4 bits,
         * where the least significant bit represents native navigation capability.
         *
         * For example: "B" = 1011, last bit is 1, therefore native navigation capability is enabled.
         *
         * @returns {boolean} Whether the browser can open SapGui applications natively.
         */
        #hasNativeNavigationCapability () {
            return this.#isFeatureBitEnabled(1);
        }

        /**
         * Determines whether the input "oResolvedNavigationTarget" represents a WebGui application that can be navigated natively by the browser.
         *
         * @param {object} oResolvedNavigationTarget The resolution result. Contains at least the "applicationType" property.
         * @returns {boolean} true if the resolution result represents a response which is to be treated by the Fiori Desktop client.
         * @private
         */
        isNativeWebGuiNavigation (oResolvedNavigationTarget) {
            if (!this.#hasNativeNavigationCapability()) {
                return false;
            }

            const sApplicationType = ObjectPath.get("applicationType", oResolvedNavigationTarget);
            const bNativeNWBCNavigationByAppCapability = ObjectPath.get("appCapabilities.nativeNWBCNavigation", oResolvedNavigationTarget);

            if (bNativeNWBCNavigationByAppCapability || sApplicationType === "TR") {
                return true;
            }

            return false;
        }

        /**
         * Detects whether NWBC can accept the navigation mode parameter.
         *
         * NWBC exposes a feature bit vector via the "getNwbcFeatureBits" method of the private "epcm" object.
         * This is expected to be a string in hex format representing 4 bits,
         * where the second most significant bit represents the capability to accept the navigation mode parameter.
         *
         * For example: "B" = 1011, the second most significant is 0,
         * therefore the capability to accept the navigation mode parameter is not enabled.
         *
         * @returns {boolean} Whether NWBC can accept the navigation mode parameter.
         */
        hasNavigationModeCapability () {
            return this.#isFeatureBitEnabled(4);
        }

        doNavigate (sUrl, sNavigationMode, oPostParams) {
            let iMode;
            if (this.hasNavigationModeCapability()) {
                iMode = oEPCMNavigationMode[sNavigationMode] || oEPCMNavigationMode.embedded;
            }

            return this.getPrivateEpcm().doNavigate(
                sUrl,
                iMode,
                undefined,
                undefined,
                undefined,
                undefined,
                undefined,
                oPostParams
            );
        }

        /**
         * Detects whether NWBC can be notified that the Container and its services are ready to be used.
         *
         * NWBC exposes a feature bit vector via the "getNwbcFeatureBits" method of the private "epcm" object.
         * This is expected to be a string in hex format representing 4 bits,
         * where the most significant bit represents the FLP ready notification capability.
         *
         * For example: "B" = 1011, the most significant bit is 1, therefore the FLP ready notification capability is enabled.
         *
         * @returns {boolean} Whether NWBC can be notified that the Container and its services are ready to be used.
         */
        #hasFLPReadyNotificationCapability () {
            return this.#isFeatureBitEnabled(8);
        }

        /**
         * Detects whether NWBC can be notified that the Container and its services are ready to be used
         * and NWBC also supports the using of FLP interface for calling some FLP apis exposed to it via interface.
         *
         * NWBC exposes a feature bit vector via the "getNwbcFeatureBits" method of the private "epcm" object.
         * This is expected to be a string in hex format representing 4 bits,
         * where the most significant bit represents the FLP ready notification capability.
         *
         * For example: "B" = 1011, the most significant bit is 1, therefore the FLP ready notification capability is enabled.
         *
         * @returns {boolean} Whether NWBC can be notified that the Container and its services are ready to be used.
         */
        #hasFLPReady2NotificationCapability () {
            return this.#isFeatureBitEnabled(16);
        }

        async doEventFlpReady () {
            if (this.#hasFLPReady2NotificationCapability()) {
                // Notify SAP Business Client (NWBC), that the Container and its Services, are ready to be used and
                // send additional interface
                const [SessionInterface] = await requireAsync(["sap/ushell/api/SAPBusinessClient/SessionInterface"]);
                this.getPrivateEpcm().doEventFlpReady2(SessionInterface);
            } else if (this.#hasFLPReadyNotificationCapability()) {
                // Notify SAP Business Client (NWBC), that the Container and its Services, are ready to be used.
                this.getPrivateEpcm().doEventFlpReady();
            }
        }

        /**
         * Determines whether a certain NWBC feature is enabled using the NWBC feature bit vector.
         *
         * @param {int} iFeatureBit The position of the feature bit to check, starting from the rightmost bit of the NWBC feature bit vector.
         * @returns {boolean} Whether the feature bit is enabled or not.
         */
        #isFeatureBitEnabled (iFeatureBit) {
            let sFeaturesHex = "0";

            // try to get the feature version number
            const oPrivateEpcm = this.getPrivateEpcm();
            if (oPrivateEpcm) {
                try {
                    sFeaturesHex = oPrivateEpcm.getNwbcFeatureBits();
                    Log.debug(`Detected epcm getNwbcFeatureBits returned feature bits: ${sFeaturesHex}`);
                } catch (oError) {
                    Log.error("failed to get feature bit vector via call getNwbcFeatureBits on private epcm object", oError, "sap.ushell.utils");
                }
            }
            return (parseInt(sFeaturesHex, 16) & iFeatureBit) > 0;
        }

        getLocationHref () {
            return window.location.href;
        }
    }

    return new SAPBusinessClientEnablement();
});
