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

sap.ui.define([
    "sap/ui/core/Element",
    "sap/ushell/Config",
    "sap/ushell/Container",
    "sap/ushell/modules/loader/AbstractLoader",
    "sap/ushell/modules/ProductSwitch/ProductSwitchAPI",
    "sap/ushell/resources",
    "sap/ushell/state/StateManager"
], (
    Element,
    Config,
    Container,
    AbstractLoader,
    ProductSwitchAPI,
    ushellResources,
    StateManager
) => {
    "use strict";
    const sConfigBasePath = "/core/productSwitch";

    // shortcut for sap.ushell.state.StateManager.Operation
    const Operation = StateManager.Operation;

    /**
     * ProductSwitch component for the Fiori Launchpad.
     *
     * @augments sap.ushell.modules.loader.AbstractLoader
     * @since 1.144.0
     * @private
     */
    class ProductSwitchLoader extends AbstractLoader {
        /**
         * The instance of the loaded product switch module.
         *
         * @type {sap.ushell.modules.ProductSwitch.ProductSwitchProvider|null}
         * @since 1.144.0
         * @private
         */
        #oModuleInstance;

        /**
         * The API object passed to the product switch module.
         *
         * @type {sap.ushell.modules.ProductSwitch.ProductSwitchAPI}
         * @since 1.144.0
         * @private
         */
        #oModuleAPI;

        /**
         * A promise that resolves when the loader is initialized.
         * @type {Promise}
         */
        #pInitialized;

        #oFrameBoundExtensionItem;

        /**
         * Creates a new instance of the ProductSwitchLoader.
         *
         * @since 1.144.0
         * @private
         */
        constructor () {
            super();
            this.#init();
        }

        /**
         * Initializes the loader by setting up a listener for configuration changes.
         * Loads or unloads the product switch module based on the configuration.
         *
         * @returns {Promise} A promise that resolves when the initialization is complete.
         * @since 1.144.0
         * @private
         */
        async #init () {
            this.registerConfigListener(sConfigBasePath, async () => {
                const bEnabled = Config.last(`${sConfigBasePath}/enabled`);
                StateManager.updateAllBaseStates("header.productSwitch.visible", Operation.Set, bEnabled);
                await this.#cleanup();
                if (bEnabled) {
                    await this.#ensureProductSwitchButton();
                    this.#oModuleInstance = await this.#load();
                }
                this.#pInitialized.resolve();
            });
        }

        /**
         * Returns a promise that resolves when the loader is initialized.
         * @returns {Promise} A promise that resolves when the loader is initialized.
         * @since 1.144.0
         * @private
         */
        initialized () {
            return this.#pInitialized.promise;
        }

        #isShellHeader () {
            const oShellHeader = Element.getElementById("shell-header");
            return oShellHeader && oShellHeader.isA("sap.ushell.ui.ShellHeader");
        }

        async #ensureProductSwitchButton () {
            if (!this.#isShellHeader()) {
                return;
            }

            if (!this.#oFrameBoundExtensionItem) {
                const FrameBoundExtension = await Container.getServiceAsync("FrameBoundExtension");
                this.#oFrameBoundExtensionItem = await FrameBoundExtension.createHeaderItem({
                    id: "productSwitchBtn",
                    icon: "sap-icon://grid",
                    visible: true,
                    text: ushellResources.i18n.getText("productSwitch"),
                    ariaHaspopup: "dialog"
                });

                this.#oFrameBoundExtensionItem.showOnHome();
                this.#oFrameBoundExtensionItem.showForAllApps();
            }
            return this.#oFrameBoundExtensionItem;
        }

        /**
         * Loads the product switch module and creates an instance of it.
         *
         * @returns {Promise<sap.ushell.modules.ProductSwitch.ProductSwitchProvider>} A promise that resolves to the product switch module instance.
         * @since 1.144.0
         * @private
         */
        async #load () {
            this.#oModuleAPI = new ProductSwitchAPI(this.parseJSONFromConfig(`${sConfigBasePath}/configuration`));

            // load the module
            return this.loadModule(Config.last(`${sConfigBasePath}/modulePath`), this.#oModuleAPI);
        }

        /**
         * Resets the loader by cleaning up the current module instance and re-initializing it.
         *
         * @returns {Promise} A promise that resolves when the module instance is destroyed and references are cleared.
         * @since 1.144.0
         * @private
         */
        async reset () {
            await this.exit();
            await this.#init();
        }

        /**
         * Cleans up the current module instance and clears the API reference.
         * @returns {Promise} A promise that resolves when the cleanup is complete.
         * @since 1.144.0
         * @private
         */
        async #cleanup () {
            if (this.#oModuleInstance && typeof this.#oModuleInstance.exit === "function") {
                await this.#oModuleInstance.exit();
            }
            this.#oModuleAPI = null;
            this.#oModuleInstance = null;
            this.#oFrameBoundExtensionItem?.destroy();
            this.#oFrameBoundExtensionItem = null;
            this.#pInitialized = Promise.withResolvers();
        }

        /**
         * Cleans up the loader by resetting the module instance and calling the superclass exit method.
         *
         * @returns {Promise} A promise that resolves when the loader is cleaned up.
         * @since 1.144.0
         * @private
         * @override
         */
        async exit () {
            await super.exit();
            await this.#cleanup();
        }
    }
    return new ProductSwitchLoader();
});
