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

/**
 * @fileoverview This file contains the StatefulContainerV2Handler class.
 * It handles the lifecycle of stateful container V2 applications.
 */
sap.ui.define([
    "sap/ushell/ApplicationType/UrlPostProcessing",
    "sap/ui/thirdparty/hasher",
    "sap/ushell/utils",
    "sap/ushell/Container"
], (
    UrlPostProcessing,
    hasher,
    ushellUtils,
    Container
) => {
    "use strict";

    /**
     * @alias sap.ushell.appIntegration.contracts.StatefulContainerV2Handler
     * @class
     * @classdesc Handles stateful container operations for V2 protocol.
     * Supports application creation, destruction, storage, and restoration.
     * Can only be used for {@link sap.ushell.appIntegration.IframeApplicationContainer} which implement the StatefulContainerV2 contract.
     *
     * @private
     */
    class StatefulContainerV2Handler {
        /**
         * Creates an application in a V2 stateful container.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @param {string} sStorageAppId The storage application ID.
         * @param {object} oResolvedHashFragment The resolved hash fragment.
         * @returns {Promise<any>} Resolves with the creation result.
         *
         * @private
         */
        async createApp (oApplicationContainer, sStorageAppId, oResolvedHashFragment) {
            oApplicationContainer.setReservedParameters(oResolvedHashFragment.reservedParameters);
            oApplicationContainer.setCurrentAppUrl(oResolvedHashFragment.url);
            oApplicationContainer.setCurrentAppId(sStorageAppId);
            oApplicationContainer.setCurrentAppTargetResolution(oResolvedHashFragment);

            const oPostParams = await this.#createPostParams(oApplicationContainer, sStorageAppId, oResolvedHashFragment);
            const oResult = await oApplicationContainer.sendRequest("sap.ushell.services.appLifeCycle.create", oPostParams, true);

            return oResult?.result;
        }

        /**
         * Creates the post message parameters for application creation in a V2 stateful container.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @param {string} sStorageAppId The storage application ID.
         * @param {object} oResolvedHashFragment The resolved hash fragment.
         * @returns {Promise<object>} The post message parameters.
         *
         * @private
         */
        async #createPostParams (oApplicationContainer, sStorageAppId, oResolvedHashFragment) {
            const sUrl = await UrlPostProcessing.processUrl(
                oResolvedHashFragment.url,
                oResolvedHashFragment.applicationType,
                false, // bForExplaceNavigation
                oApplicationContainer
            );

            const oPostParams = {
                sCacheId: sStorageAppId,
                sHash: hasher.getHash(),
                sUrl: sUrl
            };

            if (sUrl.indexOf("sap-iframe-hint=GUI") > 0 || sUrl.indexOf("sap-iframe-hint=WDA") > 0 || sUrl.indexOf("sap-iframe-hint=WCF") > 0) {
                const oAppStatesInfo = ushellUtils.getParamKeys(sUrl);
                const oFLPParams = {};

                if (oAppStatesInfo.aAppStateNamesArray.length > 0) {
                    try {
                        const Navigation = await Container.getServiceAsync("Navigation");
                        const aDataArray = await Navigation.getAppStateData(oAppStatesInfo.aAppStateKeysArray);
                        oAppStatesInfo.aAppStateNamesArray.forEach((sParamName, iIndex) => {
                            if (aDataArray[iIndex]) {
                                oFLPParams[sParamName] = aDataArray[iIndex];
                            }
                        });
                    } catch {
                        // fail silently
                    }
                }

                oPostParams["sap-flp-params"] = {
                    ...oFLPParams,
                    "sap-flp-url": Container.getFLPUrl(true),
                    "system-alias": oApplicationContainer.getSystemAlias()
                };
            }

            return oPostParams;
        }

        /**
         * Destroys an application in a V2 stateful container.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @param {string} sStorageKey The storage key for the application.
         * @returns {Promise} Resolves when the application is destroyed.
         *
         * @private
         */
        async destroyApp (oApplicationContainer, sStorageKey) {
            const bIsActiveApp = oApplicationContainer.getCurrentAppId() === sStorageKey;

            if (bIsActiveApp) {
                oApplicationContainer.setCurrentAppUrl("");
                oApplicationContainer.setCurrentAppId("");
                oApplicationContainer.setCurrentAppTargetResolution(undefined);
            }

            await oApplicationContainer.sendRequest("sap.ushell.services.appLifeCycle.destroy", {
                sCacheId: sStorageKey
            }, true);
        }

        /**
         * Stores an application within the same frame for later restoration.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @param {string} sStorageKey The storage key for the application.
         * @returns {Promise} Resolves when the application is stored.
         *
         * @private
         */
        async storeAppWithinSameFrame (oApplicationContainer, sStorageKey) {
            const bIsActiveApp = oApplicationContainer.getCurrentAppId() === sStorageKey;
            if (!bIsActiveApp) {
                throw new Error("Cannot store an already stored/destroyed app");
            }

            oApplicationContainer.setCurrentAppUrl("");
            oApplicationContainer.setCurrentAppId("");
            oApplicationContainer.setCurrentAppTargetResolution(undefined);

            await oApplicationContainer.sendRequest("sap.ushell.services.appLifeCycle.store", {
                sCacheId: sStorageKey
            }, true);
        }

        /**
         * Restores an application within the same frame.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @param {string} sStorageKey The storage key for the application.
         * @param {object} oResolvedHashFragment The resolved hash fragment.
         * @returns {Promise} Resolves when the application is restored.
         *
         * @private
         */
        async restoreAppWithinSameFrame (oApplicationContainer, sStorageKey, oResolvedHashFragment) {
            oApplicationContainer.setCurrentAppUrl(oResolvedHashFragment.url);
            oApplicationContainer.setCurrentAppId(sStorageKey);
            oApplicationContainer.setCurrentAppTargetResolution(oResolvedHashFragment);

            await oApplicationContainer.sendRequest("sap.ushell.services.appLifeCycle.restore", {
                sCacheId: sStorageKey,
                sUrl: oResolvedHashFragment.url,
                sHash: hasher.getHash()
            }, true);
        }

        /**
         * Checks if a stateful container supports keep-alive within the same frame.
         * @param {sap.ushell.appIntegration.IframeApplicationContainer} oApplicationContainer The application container.
         * @returns {boolean} True if keep-alive is supported.
         *
         * @private
         */
        isStatefulContainerSupportingKeepAlive (oApplicationContainer) {
            return oApplicationContainer.supportsCapabilities([
                // stateful capabilities
                "sap.ushell.services.AppLifeCycle.create",
                "sap.ushell.services.appLifeCycle.destroy",
                // keep alive capabilities
                "sap.ushell.services.appLifeCycle.store",
                "sap.ushell.services.appLifeCycle.restore"
            ]);
        }
    }

    return new StatefulContainerV2Handler();
});
