import { Arrays, Option } from "@opendaw/lib-std";
const Root = { type: "root" };
export class MenuItem {
    static root() { return this.#create(Root); }
    static header(properties) {
        return this.#create({ type: "header", ...properties }, properties);
    }
    static default(properties) {
        return this.#create({ type: "default", ...properties }, properties);
    }
    static inputValue(properties) {
        return this.#create({ type: "input-value", ...properties }, properties);
    }
    static #create(data, options) {
        return new MenuItem(data, options);
    }
    #data;
    #permanentChildren;
    #runtimeChildren;
    #collectors;
    #runtimeChildrenProcedure = Option.None;
    #openingProcedure = Option.None;
    #triggerProcedure = Option.None;
    #separatorBefore;
    #selectable;
    #hidden;
    #isOpening = false;
    constructor(data, options) {
        this.#data = data;
        this.#selectable = options?.selectable ?? true;
        this.#hidden = options?.hidden ?? false;
        this.#separatorBefore = options?.separatorBefore ?? false;
        this.#permanentChildren = [];
        this.#runtimeChildren = [];
        this.#collectors = [];
    }
    get data() { return this.#data; }
    get hidden() { return this.#hidden; }
    get selectable() { return this.#selectable; }
    get separatorBefore() { return this.#separatorBefore; }
    get hasChildren() {
        return this.#permanentChildren.length > 0 || this.#runtimeChildrenProcedure.nonEmpty() || this.#collectors.length > 0;
    }
    addMenuItem(...items) {
        if (this.#isOpening) {
            this.#runtimeChildren.push(...items);
        }
        else {
            this.#permanentChildren.push(...items);
        }
        return this;
    }
    open() {
        this.#openingProcedure.ifSome(procedure => procedure(this));
    }
    trigger() {
        try {
            console.debug(`MenuItem.trigger: ${JSON.stringify(this.#data)}`);
        }
        catch (reason) {
            console.debug(`MenuItem.trigger: ${this.#data}`);
        }
        this.#triggerProcedure.ifSome(procedure => procedure(this));
    }
    isSelectable(value = true) {
        this.#selectable = value;
        return this;
    }
    isHidden(value = true) {
        this.#hidden = value;
        return this;
    }
    addSeparatorBefore() {
        this.#separatorBefore = true;
        return this;
    }
    attach(populator) {
        this.#collectors.push(populator);
        return { terminate: () => Arrays.remove(this.#collectors, populator) };
    }
    setRuntimeChildrenProcedure(procedure) {
        this.#runtimeChildrenProcedure = Option.wrap(procedure);
        return this;
    }
    setOpeningProcedure(procedure) {
        this.#openingProcedure = Option.wrap(procedure);
        return this;
    }
    setTriggerProcedure(procedure) {
        this.#triggerProcedure = Option.wrap(procedure);
        return this;
    }
    collectChildren() {
        if (this.#runtimeChildrenProcedure.isEmpty() && this.#collectors.length === 0) {
            return this.#permanentChildren;
        }
        this.#isOpening = true;
        if (this.#collectors.length > 0) {
            let separatorBefore = false;
            this.#collectors.forEach(collector => collector({
                addItems: (...items) => {
                    items.forEach((item) => {
                        if (separatorBefore) {
                            item.addSeparatorBefore();
                        }
                        this.#runtimeChildren.push(item);
                        separatorBefore = false;
                    });
                    separatorBefore = true;
                }
            }));
        }
        this.#runtimeChildrenProcedure.ifSome(procedure => procedure(this));
        this.#isOpening = false;
        return this.#permanentChildren.concat(this.#runtimeChildren);
    }
    clearRuntimeProcedure() {
        this.removeRuntimeChildren();
        this.#runtimeChildrenProcedure = Option.None;
    }
    removeRuntimeChildren() {
        Arrays.clear(this.#runtimeChildren);
    }
}
