import { deepGet, defineSmartGetter } from '../utils';
export const resetToInitial = Symbol.for('@pega/cosmos-react-core.theme.resetToInitial');
class ThemeMachine {
    parent;
    definition;
    overrides;
    theme;
    overrideInTree(keys) {
        let ancestor = this;
        const fullProp = keys.join('.');
        while (ancestor) {
            // Trigger getters in the ancestor themes.
            deepGet(ancestor.theme, keys);
            if (ancestor.overrides.has(fullProp))
                return !!ancestor.overrides.get(fullProp);
            ancestor = ancestor.parent;
        }
        return false;
    }
    constructTheme(theme) {
        const constructForNode = (keys = []) => {
            const themeNode = {};
            Object.keys(deepGet(this.definition, keys)).forEach(key => {
                // Ignore comment nodes.
                if (key === '$comment')
                    return;
                const propKeys = [...keys, key];
                const defNode = deepGet(this.definition, propKeys);
                // If it is not a leaf node of the theme definition...
                if (defNode.$type === undefined) {
                    // recursively run for child nodes.
                    defineSmartGetter(themeNode, key, () => constructForNode(propKeys));
                    return;
                }
                const themeValue = deepGet(theme, propKeys);
                // If a theme value was set for this ThemeMachine...
                if (themeValue !== undefined) {
                    // set overrides to true, unless it is being reset.
                    this.overrides.set(propKeys.join('.'), themeValue !== resetToInitial);
                }
                // If a theme value was set for this ThemeMachine, is not being reset, and is for a non-constant property...
                if (themeValue !== undefined && themeValue !== resetToInitial && !defNode.$constant) {
                    // set to the provided value.
                    themeNode[key] = themeValue;
                }
                // If the property has been overridden in the tree (and not reset)...
                else if (this.overrideInTree(propKeys)) {
                    // set to the value in the parent theme.
                    defineSmartGetter(themeNode, key, () => deepGet(this.parent.theme, propKeys));
                }
                // If the property type is inherited...
                else if (defNode.$type === 'inherited') {
                    // set to the value of the inherited property in this theme.
                    defineSmartGetter(themeNode, key, () => deepGet(this.theme, defNode.$value.split('.')));
                }
                // If the property type is literal...
                else if (defNode.$type === 'literal') {
                    // set to the value listed in the definition.
                    themeNode[key] = defNode.$value;
                }
            });
            return themeNode;
        };
        return constructForNode();
    }
    constructor({ theme = {}, parent, definition }) {
        this.parent = parent ?? null;
        this.definition = parent ? parent.definition : definition;
        this.overrides = new Map();
        this.theme = this.constructTheme(theme);
    }
}
export default ThemeMachine;
//# sourceMappingURL=ThemeMachine.js.map