// Copyright (c) 2009-2026 SAP SE, All Rights Reserved

/**
 * @fileOverview This module contains Smart Business specific functionality
 */
sap.ui.define([
    "sap/base/util/deepClone",
    "sap/ushell/utils",
    "sap/ushell/Container",
    "sap/ui/core/Lib"
], (
    deepClone,
    ushellUtils,
    Container,
    Library
) => {
    "use strict";

    /**
     * @class
     * @classdesc Utility functions for Smart Business
     *
     * Smart Business implements some logic in their custom tiles that needs support
     * from ushell side.
     *
     * @private
     */
    class SmartBusiness {
        #pStoredEvaluationIdResolutionResult = null;
        #oSmartBusinessLibraryUtils = null;

        /**
         * Some Smart Business tiles do not have static navigation parameters that could be stored in the FLP content.
         * Instead the navigation parameters have to be resolved during navigation.
         * Those tiles contain parameter sap-ssb-eval-id in the FLP content that is resolved by the FLP during navigation.
         *
         * @param {object} oParsedHash The navigation parameters of this parsed shell hash are updated with the Smart Business parameters
         * @param {boolean} [bStoreResult] Store the result for later use during a direct app start
         * @returns {Promise<sap.ushell.services.URLParsing.DecomposedHash>} Resolves when the evaluation ID has been processed with the updated parsed hash.
         */
        async resolveEvaluationId (oParsedHash, bStoreResult) {
            const oParsedHashClone = deepClone(oParsedHash);
            const sEvaluationId = oParsedHashClone.params["sap-ssb-eval-id"] && oParsedHashClone.params["sap-ssb-eval-id"][0];

            if (!sEvaluationId) {
                return oParsedHashClone;
            }

            // Use the target parameters that were already resolved during the direct app start.
            // This is necessary as the Smart Business parameters are stored in an app state,
            // so the app state from the direct app start has to be used later on in the navigation filter.
            if (this.#pStoredEvaluationIdResolutionResult) {
                // It is not checked if the parameters match the first call. This is the same as
                // for the direct app start promise. It is just expected that the two calls match.
                const pResult = this.#pStoredEvaluationIdResolutionResult;
                // make sure the property is cleared in case the await throws
                this.#pStoredEvaluationIdResolutionResult = null;
                oParsedHashClone.params = (await pResult).params;
                return oParsedHashClone;
            }

            let oDeferred;
            if (bStoreResult) {
                oDeferred = Promise.withResolvers();
                this.#pStoredEvaluationIdResolutionResult = oDeferred.promise;
            }

            try {
                const oSmartBusinessLibraryUtils = await this.#getSmartBusinessLibraryUtils();
                const oSmartBusinessNavigationParameters = await oSmartBusinessLibraryUtils.getNavigationParametersForEvaluationId(sEvaluationId);

                // The navigation API has the transformation of parameter sap-xapp-state-data already build in.
                // However, as this is also needed for the direct app start the app state is created here.
                if (oSmartBusinessNavigationParameters?.["sap-xapp-state-data"]) {
                    const oAppStateService = await Container.getServiceAsync("AppState");
                    const oAppState = oAppStateService.createEmptyAppState();
                    oAppState.setData(JSON.parse(oSmartBusinessNavigationParameters["sap-xapp-state-data"]));
                    await oAppState.save();

                    delete oSmartBusinessNavigationParameters["sap-xapp-state-data"];
                    oSmartBusinessNavigationParameters["sap-xapp-state"] = oAppState.getKey();
                }

                delete oParsedHashClone.params["sap-ssb-eval-id"];
                Object.assign(oParsedHashClone.params, oSmartBusinessNavigationParameters);

                oDeferred?.resolve(oParsedHashClone);
                return oParsedHashClone;
            } catch (oError) {
                oDeferred?.reject(oError);
                throw oError;
            }
        }

        /**
         * Loads the Smart Business library.
         * Smart Business uses the same namespace for different platforms.
         * The path it is loaded from might have to be adapted for the specific platform.
         * Usually this mapping is done by Smart Business. It only has to be done
         * by the ushell if Smart Business has not been loaded yet,
         * e.g. during the direct app start.
         *
         * @param {string} [sPath] The platform specific path
         * @returns {Promise} A promise that resolves when the library is loaded
         */
        loadSmartBusinessLibrary (sPath) {
            if (sPath) {
                sap.ui.loader.config({
                    paths: {
                        "sap/cloudfnd/smartbusiness/lib/reusetiles": sPath
                    }
                });
            }

            return Library.load({
                name: "sap.cloudfnd.smartbusiness.lib.reusetiles"
            });
        }

        /**
         * Loads and returns the Smart Business library utils instance.
         * Instantiates the util UI component if not already available.
         *
         * @private
         * @returns {Promise<object>} Resolves to the Smart Business library utils instance
         */
        async #getSmartBusinessLibraryUtils () {
            if (!this.#oSmartBusinessLibraryUtils) {
                // If the Smart Business library is not available the module loading throws and we enter the normal error handling flow
                const [SmartBusinessLibraryUtilsUiComponent] = await ushellUtils.requireAsync(["sap/cloudfnd/smartbusiness/lib/reusetiles/Util"]);
                // It was aligned with Smart Business that this util UI component shall be instantiated in the FLP coding again
                this.#oSmartBusinessLibraryUtils = new SmartBusinessLibraryUtilsUiComponent();
            }
            return this.#oSmartBusinessLibraryUtils;
        }
    }

    return new SmartBusiness();
});
