"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PostTransactionValue = void 0;
const internal_1 = require("../internal");
const types_1 = require("../types");
/**
 * @hidden
 *
 * Represents a value or method that doesn't exist at the moment, but will exist once a certain transaction
 *   has been run
 */
class PostTransactionValue {
    // eslint-disable-next-line require-jsdoc
    constructor(resolver, runCondition = () => true) {
        this.resolved = false;
        /**
         * Array of PostTransactionValues spawned by this one via `transform` or `merge`. We use this to keep track
         */
        this.children = [];
        this.resolver = resolver;
        this.runCondition = runCondition;
    }
    /**
     * Run the resolver function and assign its result to this object
     */
    run(receipt) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.runCondition()) {
                return;
            }
            const result = yield this.resolver(receipt);
            this.resolved = true;
            this._value = result;
            yield Promise.all(this.children.map(child => child.run(receipt)));
        });
    }
    /**
     * Retrieve the resolved value
     *
     * @throws if the value is being accessed before the resolver function has run
     */
    get value() {
        const { _value: value, resolved } = this;
        if (!resolved) {
            throw new internal_1.PolymeshError({
                code: types_1.ErrorCode.FatalError,
                message: 'Post Transaction Value accessed before the corresponding transaction was executed',
            });
        }
        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
        return value;
    }
    /**
     * Add a new PostTransactionValue to the children array to be run when this one runs
     */
    addChild(child) {
        this.children.push(child);
    }
    /**
     * Return a new PostTransactionValue that resolves to the value of this one processed by
     *   the passed callback. The new PostTransactionValue is resolved when this one is resolved
     */
    transform(callback) {
        const newResolver = () => {
            return callback(this.value);
        };
        const child = new PostTransactionValue(newResolver);
        this.addChild(child);
        return child;
    }
    /**
     * Merge this PostTransactionValue with another PostTransactionValue (or plain value), resulting in a new
     *   PostTransactionValue that resolves once these two are resolved. The resolved value is the result of passing the
     *   resolved values of both PostTransactionValues to the callback
     */
    merge(postValue, callback) {
        let newResolver;
        let runCondition;
        // do nothing on .run unless both underlying values have been resolved
        if (postValue instanceof PostTransactionValue) {
            newResolver = () => callback(this.value, postValue.value);
            runCondition = () => this.resolved && postValue.resolved;
        }
        else {
            newResolver = () => callback(this.value, postValue);
            runCondition = () => this.resolved;
        }
        const child = new PostTransactionValue(newResolver, runCondition);
        this.addChild(child);
        if (postValue instanceof PostTransactionValue) {
            postValue.addChild(child);
        }
        return child;
    }
}
exports.PostTransactionValue = PostTransactionValue;
//# sourceMappingURL=PostTransactionValue.js.map