"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.takeSideDialogResponses = takeSideDialogResponses;
exports.commitTakenSideDialogResponses = commitTakenSideDialogResponses;
exports.rollbackTakenSideDialogResponses = rollbackTakenSideDialogResponses;
exports.withSideDialogTxnLock = withSideDialogTxnLock;
exports.withSideDialogTxnLocks = withSideDialogTxnLocks;
const persistence_1 = require("../../persistence");
const async_fifo_mutex_1 = require("../../runtime/async-fifo-mutex");
const suspensionStateMutexes = new Map();
async function withSuspensionStateLock(dialogId, fn) {
    const key = dialogId.key();
    let mutex = suspensionStateMutexes.get(key);
    if (!mutex) {
        mutex = new async_fifo_mutex_1.AsyncFifoMutex();
        suspensionStateMutexes.set(key, mutex);
    }
    const release = await mutex.acquire();
    try {
        return await fn();
    }
    finally {
        release();
        if (suspensionStateMutexes.get(key) === mutex && !mutex.isLocked()) {
            suspensionStateMutexes.delete(key);
        }
    }
}
async function takeSideDialogResponses(dialogId) {
    return await withSuspensionStateLock(dialogId, async () => {
        return await persistence_1.DialogPersistence.takeSideDialogResponses(dialogId);
    });
}
async function commitTakenSideDialogResponses(dialogId) {
    await withSuspensionStateLock(dialogId, async () => {
        await persistence_1.DialogPersistence.commitTakenSideDialogResponses(dialogId);
    });
}
async function rollbackTakenSideDialogResponses(dialogId) {
    await withSuspensionStateLock(dialogId, async () => {
        await persistence_1.DialogPersistence.rollbackTakenSideDialogResponses(dialogId);
    });
}
async function withSideDialogTxnLock(dialogId, fn) {
    return await withSuspensionStateLock(dialogId, fn);
}
async function withSideDialogTxnLocks(dialogIds, fn) {
    const ordered = [
        ...new Map(dialogIds.map((dialogId) => [dialogId.key(), dialogId])).values(),
    ].sort((left, right) => left.key().localeCompare(right.key()));
    let index = 0;
    const run = async () => {
        if (index >= ordered.length) {
            return await fn();
        }
        const dialogId = ordered[index];
        index += 1;
        return await withSuspensionStateLock(dialogId, run);
    };
    return await run();
}
