/* eslint-disable @typescript-eslint/no-this-alias */
import { drop, findLast, pull } from 'lodash';
import { FormObjectVariable, FormRepeatableVariable } from '../form/FormVariable.js';
import { JinjaContextValue } from './JinjaContextValue.js';
import { JinjaObjectVariable } from './JinjaVariable.js';
function getVariableInPath(variable, path) {
    const [head, ...tail] = path;
    if (!head)
        return tail.length ? getVariableInPath(variable, tail) : variable;
    if (variable instanceof FormRepeatableVariable) {
        return getVariableInPath(variable.condensed, path);
    }
    if (variable instanceof FormObjectVariable || variable instanceof JinjaObjectVariable) {
        const child = variable.children[head];
        if (!child || (Array.isArray(child) && !child.length))
            return variable;
        return getVariableInPath(Array.isArray(child) ? findLast(child, v => v.getState().visible) : child, tail);
    }
    return variable;
}
function contextHasKey(context, key) {
    return (context instanceof JinjaContextValue && context.prefix === key) ? true : context.has(key);
}
export class ContextValue {
    constructor(name) {
        Object.defineProperty(this, "name", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
        Object.defineProperty(this, "changeVariableSetupListeners", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        });
        this.name = name;
    }
    createKey(key) {
        return String(key);
    }
    has(key) {
        return !!this.findVariableByKey(key);
    }
    getVariable(path, ignore) {
        let current = this;
        path = path.trim();
        let [head, ...tail] = path.split(/[.[\]]/);
        while (current && (ignore?.includes(current.name ?? '') || !contextHasKey(current, head)))
            current = current.parent;
        if (current instanceof JinjaContextValue && current.prefix) {
            if (current.prefix !== head)
                return;
            head = tail[0];
            tail = drop(tail);
        }
        const variable = current?.findVariableByKey(head);
        return variable ? getVariableInPath(variable, tail) : undefined;
    }
    get(key, ignore) {
        return this.getVariable(key, ignore)?.get();
    }
    getInContext(key) {
        return this.getVariableInContext(key)?.get();
    }
    getAll(ignore) {
        let current = this;
        const branch = [];
        while (current) {
            if (!ignore?.includes(current.name ?? ''))
                branch.push(current);
            current = current.parent;
        }
        let variables = {};
        for (let i = branch.length - 1; i >= 0; i--) {
            variables = { ...variables, ...branch[i].getAll() };
        }
        return variables;
    }
    set(key, value) {
        this.findVariableByKey(this.createKey(key))?.set(value);
    }
    onChange(key, listener) {
        return this.findVariableByKey(this.createKey(key))?.onChange(listener) ?? (() => { });
    }
    closest(name) {
        let current = this;
        while (current && current.name !== name)
            current = current.parent;
        return current;
    }
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    addVariablesToContext(_variables) {
        // this looks like a bug in Typescript. Declaring protected abstract methods don't work.    
    }
    onChangeVariableSetup(listener) {
        this.changeVariableSetupListeners.push(listener);
        return () => {
            pull(this.changeVariableSetupListeners, listener);
        };
    }
    addVariables(variables) {
        this.addVariablesToContext(variables);
        this.changeVariableSetupListeners.forEach(l => l());
    }
}
//# sourceMappingURL=ContextValue.js.map