/* eslint-disable @typescript-eslint/naming-convention */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { Property } from '../Decorators/PropertyDecorator';
import { ThemeService } from '../../Theming/ThemeService';
import { getCompatibleStyle } from 'lit';
import { ThemeObserverServiceLocator } from '@breadstone/mosaik-themes';
/**
 * @public
 */
export var IThemeableProps;
(function (IThemeableProps) {
    IThemeableProps.DEFAULTS = {
        themeName: ''
    };
})(IThemeableProps || (IThemeableProps = {}));
/**
 * @public
 */
export const Themeable = (base) => {
    class ThemeableElement extends base {
        // #region Fields
        static _themeStyles = {};
        _themeName;
        _themeChangedSubscription = null;
        // #endregion
        // #region Ctor
        /**
         * Constructs a new instance of the `ThemeableElement` class.
         *
         * @public
         */
        constructor(...args) {
            super(args);
            this._themeName = IThemeableProps.DEFAULTS.themeName;
            this._themeChangedSubscription = null;
        }
        // #endregion
        // #region Properties
        /**
         * Gets or sets the `themeName` property.
         * This property defines the name of the theme to be applied to the element.
         * If not set, the element will use the default theme.
         * The default value is an empty string, which means no theme is set.
         *
         * @public
         */
        get themeName() {
            return this._themeName;
        }
        set themeName(value) {
            if (this._themeName !== value) {
                this._themeName = value;
                this.requestUpdate('themeName');
            }
        }
        // #endregion
        // #region Methods
        /**
         * Registers the themes.
         *
         * @public
         * @static
         * @param themes - The themes to register.
         */
        static registerThemes(themes) {
            this._themeStyles = themes;
        }
        /**
         * @public
         * @override
         */
        connectedCallback() {
            super.connectedCallback();
            // if (!this._theme) {
            //     this.theme = this.getGlobalTheme();
            // }
            this._themeChangedSubscription = ThemeService.instance.themeChanged.subscribe((x) => {
                this.themeName = x?.name ?? '';
            });
            ThemeObserverServiceLocator.current.themeChanged.subscribe(() => {
                this.forceStyleUpdate();
            });
        }
        /**
         * @public
         * @override
         */
        disconnectedCallback() {
            super.disconnectedCallback();
            this._themeChangedSubscription?.dispose();
        }
        /**
         * Finalizes the styles.
         *
         * @protected
         * @param styles - The styles to finalize.
         * @returns - The finalized styles.
         */
        static finalizeStyles(styles) {
            const currentTheme = document.documentElement.getAttribute('theme');
            const themeStyles = Object.entries(this._themeStyles).find(([key]) => key === currentTheme)?.[1];
            const newStyles = [
                styles ?? [],
                themeStyles ?? []
            ];
            const finalStyles = finalizeStyles(newStyles);
            return finalStyles;
        }
        /**
         * Gets the styles for the theme.
         *
         * @protected
         */
        forceStyleUpdate() {
            const thisCtor = this.constructor;
            const superCtor = Object.getPrototypeOf(thisCtor);
            const baseFinalStyles = superCtor.finalizeStyles();
            superCtor.elementStyles = baseFinalStyles;
            // use this method carefully, it will force the styles to be updated.
            // from lit side, it's not officially supported, but it's a workaround to force the styles to be updated.
            // (this.constructor as typeof ThemeableElement).finalizeStyles();
            this.requestUpdate();
        }
    }
    __decorate([
        Property({ type: String }),
        __metadata("design:type", String),
        __metadata("design:paramtypes", [String])
    ], ThemeableElement.prototype, "themeName", null);
    return ThemeableElement;
};
function finalizeStyles(styles) {
    const elementStyles = [];
    if (Array.isArray(styles)) {
        // Dedupe the flattened array in reverse order to preserve the last items.
        // Casting to Array<unknown> works around TS error that
        // appears to come from trying to flatten a type CSSResultArray.
        const set = new Set(styles.flat(Infinity).reverse());
        // Then preserve original order by adding the set items in reverse order.
        for (const s of set) {
            elementStyles.unshift(getCompatibleStyle(s));
        }
    }
    else if (styles !== undefined) {
        elementStyles.push(getCompatibleStyle(styles));
    }
    return elementStyles;
}
//# sourceMappingURL=Themeable.js.map