import { from, isObservable, lastValueFrom, switchMap, tap, toArray } from "rxjs";
/** The main class that runs actions */
export class ActionHub {
    events;
    factory;
    publish;
    /** Whether to save all events created by actions to the event store */
    saveToStore = true;
    constructor(events, factory, publish) {
        this.events = events;
        this.factory = factory;
        this.publish = publish;
    }
    context = undefined;
    async getContext() {
        if (this.context)
            return this.context;
        else {
            if (!this.factory.context.signer)
                throw new Error("Missing signer");
            const self = await this.factory.context.signer.getPublicKey();
            this.context = { self, events: this.events, factory: this.factory };
            return this.context;
        }
    }
    /** Runs an action in a ActionContext and converts the result to an Observable */
    static runAction(ctx, action) {
        const result = action(ctx);
        if (isObservable(result))
            return result;
        else
            return from(result);
    }
    /** Run an action and publish events using the publish method */
    async run(Action, ...args) {
        if (!this.publish)
            throw new Error("Missing publish method, use ActionHub.exec");
        // wait for action to complete and group events
        const events = await lastValueFrom(this.exec(Action, ...args).pipe(toArray()));
        // publish events
        for (const event of events)
            await this.publish(event);
    }
    /** Run an action without publishing the events */
    exec(Action, ...args) {
        return from(this.getContext()).pipe(switchMap((ctx) => {
            const action = Action(...args);
            return ActionHub.runAction(ctx, action);
        }), tap((event) => this.saveToStore && this.events.add(event)));
    }
}
