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

sap.ui.define([
    "sap/base/Log",
    "sap/base/util/ObjectPath",
    "sap/base/util/extend",
    "sap/ushell/bootstrap/Config"
], (
    Log,
    ObjectPath,
    extend,
    BootstrapConfig
) => {
    "use strict";

    /**
     * @typedef {object} ThemeData
     * The theme data extracted from the ushell configuration.
     * @property {string} sDefaultTheme The default theme
     * @property {string} sPersonalizedTheme The personalized theme set by the user
     * @property {object} oRangeTheme The theme range defined in the configuration, with theme names as keys and theme root data as values
     *
     * @since 1.147.0
     * @private
     */

    /**
     * @typedef {object} ThemeConfig
     * The active theme configuration for the CDM platform.
     * @property {string} theme The active theme for the CDM platform
     * @property {object} themeRoots An object mapping theme names to their respective theme roots
     *
     * @since 1.147.0
     * @private
     */

    /**
     * @alias sap.ushell.bootstrap.cdm.PlatformConfig
     * @namespace
     * @description CDM platform configuration. Responsible for applying CDM-specific settings to the ushell configuration,
     * determining the active theme and theme roots, and providing the merged UI5 configuration for the CDM platform.
     *
     * @since 1.147.0
     * @private
     */
    class PlatformConfig {
        /**
         * Some settings of the ushell which are dependent on user personalization
         * are included in the config by direct reference to their respective
         * container in the personalization storage.
         *
         * This function transforms the stored key-value pairs into a structure the
         * ushell configuration processor understands.
         *
         * @since 1.147.0
         * @private
         */
        #fixUpPersonalizedSettings () {
            const oUshellConfig = BootstrapConfig.get();

            const oPersonalizedSetting = ObjectPath.get("services.Container.adapter.config.userProfilePersonalization", oUshellConfig);

            if (oPersonalizedSetting && oPersonalizedSetting.items) {
                extend(oPersonalizedSetting, oPersonalizedSetting.items);

                delete oPersonalizedSetting.items;
                delete oPersonalizedSetting.__metadata;
            }
        }

        /**
         * Activates FLP spaces (based on pages and sections therein)
         * or the classic homepage mode (based on app groups)
         * by setting the configuration switch <code>config.ushell.spaces.enabled</code> .
         *
         * @since 1.147.0
         * @private
         */
        #setSpacesOrHomepageMode () {
            const oUshellConfig = BootstrapConfig.get();
            const bSpacesConfigurableByUser = ObjectPath.get("ushell.spaces.configurable", oUshellConfig);
            if (bSpacesConfigurableByUser) {
                const bSpacesEnabledByUser = ObjectPath.get("services.Container.adapter.config.userProfilePersonalization.spacesEnabled", oUshellConfig);

                if (bSpacesEnabledByUser === true) {
                    ObjectPath.set("ushell.spaces.enabled", true, oUshellConfig);
                } else if (bSpacesEnabledByUser === false) {
                    ObjectPath.set("ushell.spaces.enabled", false, oUshellConfig);
                }
            }
        }

        /**
         * Sets the boot theme and theme list in the Container adapter configuration.
         * Reads theme data from the ushell config, determines the active theme, and
         * writes the boot theme and theme range for the UserInfo adapter.
         *
         * @since 1.147.0
         * @private
         */
        #setThemesInAdapterConfig () {
            const oUshellConfig = BootstrapConfig.get();
            const oContainerAdapterConfig = ObjectPath.get("services.Container.adapter.config", oUshellConfig);

            const { theme, themeRoots } = this.#getThemeConfig();
            const oBootTheme = {
                root: themeRoots[theme] || "",
                theme
            };

            const oThemeRange = ObjectPath.get("userProfile.metadata.ranges.theme", oContainerAdapterConfig);
            if (oThemeRange) {
                const aThemeList = Object.keys(oThemeRange).map((key) => {
                    return {
                        id: key,
                        name: oThemeRange[key].displayName,
                        root: oThemeRange[key].themeRoot
                    };
                });

                // creates path and sets theme list for UserInfo adapter
                ObjectPath.set("services.UserInfo.adapter.config.themes", aThemeList, oUshellConfig);
            }

            // does personalized or standard theme exists
            if (oBootTheme.theme) {
                ObjectPath.set("userProfile.defaults.bootTheme", oBootTheme, oContainerAdapterConfig);
            } else {
                const sDefaultTheme = ObjectPath.get("userProfile.defaults.theme", oContainerAdapterConfig);
                const sPersonalizedTheme = ObjectPath.get("userProfilePersonalization.theme", oContainerAdapterConfig);
                Log.error(`No valid boot theme could be determined: personalizedTheme = '${sPersonalizedTheme}' default theme = '${sDefaultTheme}'`, null, "cdm.PlatformConfig");
            }
        }

        /**
         * Applies cdm specific configuration to the ushell config
         *
         * @since 1.147.0
         * @private
         */
        configureUshell () {
            this.#fixUpPersonalizedSettings();
            this.#setSpacesOrHomepageMode();
            this.#setThemesInAdapterConfig();
        }

        /**
         * Extracts theme-related data from the Container adapter configuration.
         *
         * @returns {ThemeData} The theme data.
         *
         * @since 1.147.0
         * @private
         */
        #extractThemeDataFromConfig () {
            const oUshellConfig = BootstrapConfig.get();
            const oContainerAdapterConfig = ObjectPath.get("services.Container.adapter.config", oUshellConfig);
            return {
                sDefaultTheme: ObjectPath.get("userProfile.defaults.theme", oContainerAdapterConfig),
                sPersonalizedTheme: ObjectPath.get("userProfilePersonalization.theme", oContainerAdapterConfig),
                oRangeTheme: ObjectPath.get("userProfile.metadata.ranges.theme", oContainerAdapterConfig)
            };
        }

        /**
         * Determines the active theme and theme roots from configuration.
         * If a theme range is available, uses the personalized theme when it is
         * in the range, otherwise falls back to the default theme.
         *
         * @returns {ThemeConfig} The active theme configuration.
         *
         * @since 1.147.0
         * @private
         */
        #getThemeConfig () {
            const oUshellConfig = BootstrapConfig.get();
            const oThemeData = this.#extractThemeDataFromConfig(oUshellConfig);
            const sPersonalizedTheme = oThemeData.sPersonalizedTheme;
            const oRangeTheme = oThemeData.oRangeTheme;
            const sDefaultTheme = oThemeData.sDefaultTheme;

            if (oThemeData.oRangeTheme) {
                const oThemeRoots = {};
                Object.keys(oRangeTheme).forEach((sTheme) => {
                    oThemeRoots[sTheme] = oRangeTheme[sTheme].themeRoot;
                });

                // Range of themes contains boot theme
                if (Object.keys(oRangeTheme).indexOf(sPersonalizedTheme) > -1) {
                    return {
                        theme: sPersonalizedTheme,
                        themeRoots: oThemeRoots
                    };
                }
                // return DefaultTheme
                return {
                    theme: sDefaultTheme,
                    themeRoots: oThemeRoots
                };
            }
            // stay compatible
            const sAppliedTheme = sPersonalizedTheme || sDefaultTheme;
            return {
                theme: sAppliedTheme,
                themeRoots: {
                    [sAppliedTheme]: ""
                }
            };
        }

        /**
         * Returns the CDM platform-specific UI5 configuration.
         *
         * @returns {object} UI5 configuration with camelCase keys (sapUiTheme, sapUiThemeRoots, sapUiLanguage, sapUiABAPTimeFormat, etc.)
         *
         * @since 1.147.0
         * @private
         */
        getUI5Config () {
            const oUshellConfig = BootstrapConfig.get();
            const { theme, themeRoots } = this.#getThemeConfig();

            let bUseThemeRootsFromConfig = true;
            const oBootstrapTag = this.getBootstrapTag();
            if (oBootstrapTag?.hasAttribute("data-sap-ui-theme-roots") || oBootstrapTag?.hasAttribute("data-sap-ui-themeroots")) {
                Log.debug("Theme roots defined in the bootstrap tag will be ignored in favor of theme roots defined in the ushell configuration.", null, "cdm.PlatformConfig");
                bUseThemeRootsFromConfig = false;
            }

            const oContainerAdapterConfig = ObjectPath.get("services.Container.adapter.config", oUshellConfig) || {};
            const sCalendarWeekNumbering = oContainerAdapterConfig.calendarWeekNumbering || "Default";

            const oUserProfileDefaults = ObjectPath.get("userProfile.defaults", oContainerAdapterConfig) || {};
            const sLanguageBcp47 = oUserProfileDefaults.languageBcp47;
            const sSapTimeFormat = oUserProfileDefaults.sapTimeFormat;
            const sSapDateFormat = oUserProfileDefaults.sapDateFormat;

            return {
                sapUiABAPTimeFormat: sSapTimeFormat,
                sapUiABAPDateFormat: sSapDateFormat,
                sapUiLanguage: sLanguageBcp47,
                sapUiCalendarWeekNumbering: sCalendarWeekNumbering,
                sapUiTheme: theme,
                sapUiThemeRoots: bUseThemeRootsFromConfig ? themeRoots : undefined,
                sapUiOnInit: "module:sap/ushell/bootstrap/cdm/LoadLaunchpadModule"
            };
        }

        /**
         * Helper for tests
         * @returns {Node} the bootstrap tag element
         *
         * @since 1.148.0
         * @private
         */
        getBootstrapTag () {
            return document.querySelector("#sap-ui-bootstrap");
        }
    }

    return new PlatformConfig();
});
