function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
import { iconsMap } from '../static/variables/helpers/iconsMap.mjs';
import { throwWithCause } from '../../helpers/errors.mjs';
import { flattenCssVariables } from './utils/cssVariables.mjs';
/**
 * The theme prefix.
 *
 * @type {string}
 */ const THEME_PREFIX = 'ht-theme-';
var /**
   * Unsubscribes from the theme object's change notifications.
   *
   * @type {Function|null}
   */ _unsubscribeTheme = /*#__PURE__*/ new WeakMap(), /**
   * Injects theme styles into the DOM.
   */ _injectThemeStyles = /*#__PURE__*/ new WeakSet();
/**
 * ThemeManager class provides methods to manage the theme styles.
 *
 * @class ThemeManager
 */ export class ThemeManager {
    /**
   * Gets the theme class name.
   *
   * @returns {string} The theme class name.
   */ getClassName() {
        return this.themeClassName;
    }
    /**
   * Updates the theme manager.
   *
   * @param {object} themeObject - The theme object.
   */ update(themeObject) {
        var _this, _this1, _ref;
        if (!this.hot) {
            return;
        }
        if (themeObject.getThemeConfig === undefined) {
            throwWithCause('[ThemeManager] The "theme" option must be an instance of ThemeBuilder.');
        }
        this.themeConfig = themeObject.getThemeConfig();
        this.themeClassName = `${THEME_PREFIX}${this.themeConfig.name}`;
        if (typeof themeObject.subscribe === 'function') {
            (_this = _class_private_field_get(_ref = _this1 = this, _unsubscribeTheme)) === null || _this === void 0 ? void 0 : _this.call(_this1);
            _class_private_field_set(this, _unsubscribeTheme, themeObject.subscribe((config)=>{
                if (!this.hot?.stylesHandler) {
                    return;
                }
                this.themeConfig = config;
                _class_private_method_get(this, _injectThemeStyles, injectThemeStyles).call(this);
                this.hot.stylesHandler.clearCache();
                this.hot.render();
                this.hot.runHooks('afterSetTheme', this.themeClassName, false);
            }));
        }
        this.mount();
        this.hot.runHooks('afterSetTheme', this.themeClassName, true);
    }
    /**
   * Mounts the theme manager.
   */ mount() {
        _class_private_method_get(this, _injectThemeStyles, injectThemeStyles).call(this);
    }
    /**
   * Unmounts the theme manager.
   */ unmount() {
        if (this.themeStyles) {
            this.themeStyles.remove();
        }
    }
    /**
   * Destroys the theme manager.
   */ destroy() {
        var _this, _this1, _ref;
        (_this = _class_private_field_get(_ref = _this1 = this, _unsubscribeTheme)) === null || _this === void 0 ? void 0 : _this.call(_this1);
        this.unmount();
        this.hot.themeManager = null;
    }
    /**
   * The theme manager constructor.
   *
   * @param {object} options - The options object.
   * @param {Handsontable} options.hot - The Handsontable instance.
   * @param {object} options.themeObject - The theme object.
   */ constructor({ hot, themeObject }){
        _class_private_method_init(this, _injectThemeStyles);
        _class_private_field_init(this, _unsubscribeTheme, {
            writable: true,
            value: void 0
        });
        _class_private_field_set(this, _unsubscribeTheme, null);
        this.hot = hot;
        this.update(themeObject);
    }
}
function injectThemeStyles() {
    if (!this.themeConfig || !this.hot || !this.hot.rootDocument || !this.hot.rootWrapperElement) {
        return;
    }
    const colorScheme = this.themeConfig.colorScheme === 'auto' ? 'light dark' : this.themeConfig.colorScheme;
    if (this.themeStyles) {
        this.themeStyles.textContent = '';
    } else {
        this.themeStyles = this.hot.rootDocument.createElement('style');
    }
    this.themeStyles.textContent = `:where(.${this.themeClassName}) {\n`;
    if (this.themeConfig.sizing) {
        this.themeStyles.textContent += flattenCssVariables(this.themeConfig.sizing, 'sizing');
    }
    if (this.themeConfig.density && this.themeConfig.density.type && this.themeConfig.density.sizes && this.themeConfig.density.sizes[this.themeConfig.density.type]) {
        this.themeStyles.textContent += flattenCssVariables(this.themeConfig.density.sizes[this.themeConfig.density.type], 'density');
    }
    if (this.themeConfig.colors) {
        this.themeStyles.textContent += flattenCssVariables(this.themeConfig.colors, 'colors');
    }
    if (this.themeConfig.tokens) {
        this.themeStyles.textContent += flattenCssVariables(this.themeConfig.tokens);
    }
    if (this.themeConfig.icons) {
        this.themeStyles.textContent += iconsMap(this.themeConfig.icons);
    }
    this.themeStyles.textContent += '}\n';
    // Separate rule with class-level specificity (0,1,0) so this <style> (injected into <body>)
    // wins over same-specificity color-scheme declarations in static ht-theme-*.css files via
    // source order, while keeping all other tokens at :where() specificity for easy overrides.
    this.themeStyles.textContent += `.${this.themeClassName} {\ncolor-scheme: ${colorScheme};\n}`;
    if (this.hot.rootWrapperElement && this.hot.rootWrapperElement.querySelector('style')) {
        this.hot.rootWrapperElement.querySelector('style').textContent = this.themeStyles.textContent;
    } else {
        this.hot.rootWrapperElement.prepend(this.themeStyles);
    }
}
/**
 * Creates a new ThemeManager instance.
 *
 * @param {object} options - The options object.
 * @param {Handsontable} options.hot - The Handsontable instance.
 * @param {object} options.themeObject - The theme object.
 * @returns {ThemeManager} The ThemeManager instance.
 */ export function createThemeManager({ hot, themeObject }) {
    return new ThemeManager({
        hot,
        themeObject
    });
}
