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

sap.ui.define([
    "sap/ushell/Config",
    "sap/ushell/modules/loader/AbstractLoader",
    "sap/ushell/modules/Notifications/NotificationsAPI",
    "sap/ushell/state/StateManager"
], (
    Config,
    AbstractLoader,
    NotificationsAPI,
    StateManager
) => {
    "use strict";
    const sConfigBasePath = "/core/notifications";

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

    /**
     * Notifications component for the Fiori Launchpad.
     *
     * @augments sap.ushell.modules.loader.AbstractLoader
     * @since 1.142.0
     * @private
     */
    class NotificationsLoader extends AbstractLoader {
        /**
         * The instance of the loaded notifications module.
         *
         * @type {sap.ushell.modules.Notifications.NotificationsProvider|null}
         * @since 1.142.0
         * @private
         */
        #oModuleInstance;

        /**
         * The API object passed to the notifications module.
         *
         * @type {sap.ushell.modules.Notifications.NotificationsAPI}
         * @since 1.142.0
         * @private
         */
        #oModuleAPI;

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

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

        /**
         * Initializes the loader by setting up a listener for configuration changes.
         * Loads or unloads the notifications module based on the configuration.
         *
         * @returns {Promise} A promise that resolves when the initialization is complete.
         * @since 1.142.0
         * @private
         */
        async #init () {
            this.registerConfigListener("/core/notifications", async () => {
                const bEnabled = Config.last("/core/notifications/enabled");
                StateManager.updateAllBaseStates("header.notifications.visible", Operation.Set, bEnabled);
                await this.#cleanup();
                if (bEnabled) {
                    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.142.0
         * @private
         */
        initialized () {
            return this.#pInitialized.promise;
        }

        /**
         * Loads the notifications module and creates an instance of it.
         *
         * @returns {Promise<sap.ushell.modules.Notifications.NotificationsProvider>} A promise that resolves to the notifications module instance.
         * @since 1.142.0
         * @private
         */
        async #load () {
            this.#oModuleAPI = new NotificationsAPI(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.142.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.142.0
         * @private
         */
        async #cleanup () {
            if (this.#oModuleInstance && typeof this.#oModuleInstance.exit === "function") {
                await this.#oModuleInstance.exit();
            }
            this.#oModuleAPI = null;
            this.#oModuleInstance = 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.142.0
         * @private
         * @override
         */
        async exit () {
            await super.exit();
            await this.#cleanup();
        }
    }
    return new NotificationsLoader();
});
