import * as tslib_1 from "tslib";
import { of } from 'rxjs';
import { delay, map, mergeMap, tap } from 'rxjs/operators';
import { randomExponentialBackoffTimer } from '../../../helper';
import { createLogger } from '../../../logger/logger';
import { createToKeyFn, toDb } from '../../../mapper';
var MAX_BATCH_WRITE_ITEMS = 25;
var BatchWriteSingleTableRequest = /** @class */ (function () {
    function BatchWriteSingleTableRequest(dynamoRx, modelClazz, tableName) {
        this.logger = createLogger('dynamo.request.BatchWriteSingleTableRequest', modelClazz);
        this.dynamoRx = dynamoRx;
        if (modelClazz === null || modelClazz === undefined) {
            throw new Error("please provide the model clazz for the request, won't work otherwise");
        }
        this.modelClazz = modelClazz;
        this.tableName = tableName;
        this.itemsToProcess = [];
    }
    Object.defineProperty(BatchWriteSingleTableRequest.prototype, "toKey", {
        get: function () {
            if (!this.keyFn) {
                this.keyFn = createToKeyFn(this.modelClazz);
            }
            return this.keyFn;
        },
        enumerable: true,
        configurable: true
    });
    BatchWriteSingleTableRequest.prototype.delete = function (items) {
        var _this = this;
        var _a;
        (_a = this.itemsToProcess).push.apply(_a, tslib_1.__spread(items.map(function (item) { return ({ DeleteRequest: { Key: _this.toKey(item) } }); })));
        this.logger.debug(items.length + " items added for DeleteRequest");
        return this;
    };
    BatchWriteSingleTableRequest.prototype.put = function (items) {
        var _this = this;
        var _a;
        (_a = this.itemsToProcess).push.apply(_a, tslib_1.__spread(items.map(function (item) { return ({ PutRequest: { Item: toDb(item, _this.modelClazz) } }); })));
        this.logger.debug(items.length + " items added for PutRequest");
        return this;
    };
    BatchWriteSingleTableRequest.prototype.execNextBatch = function () {
        var _this = this;
        var _a;
        var batch = this.itemsToProcess.splice(0, MAX_BATCH_WRITE_ITEMS);
        var batchWriteItemInput = {
            RequestItems: (_a = {},
                _a[this.tableName] = batch,
                _a),
        };
        this.logger.debug('request', batchWriteItemInput);
        return this.dynamoRx.batchWriteItem(batchWriteItemInput).pipe(tap(function (response) { return _this.logger.debug('response', response); }), tap(function (batchWriteManyResponse) {
            var _a;
            if (batchWriteManyResponse.UnprocessedItems && batchWriteManyResponse.UnprocessedItems[_this.tableName]) {
                (_a = _this.itemsToProcess).unshift.apply(_a, tslib_1.__spread(batchWriteManyResponse.UnprocessedItems[_this.tableName]));
            }
        }), map(function (batchWriteManyResponse) { return ({
            remainingItems: _this.itemsToProcess.length,
            capacityExceeded: !!(batchWriteManyResponse.UnprocessedItems && batchWriteManyResponse.UnprocessedItems[_this.tableName]),
            consumedCapacity: batchWriteManyResponse.ConsumedCapacity,
        }); }), tap(function (response) {
            if (response.capacityExceeded) {
                _this.logger.info('capacity exceeded', response.consumedCapacity);
            }
        }));
    };
    /**
     *
     * @param backoffTimer generator for how much timeSlots should be waited before requesting next batch. only used when capacity was exceeded. default randomExponentialBackoffTimer
     * @param throttleTimeSlot defines how long one timeSlot is for throttling, default 1 second
     */
    BatchWriteSingleTableRequest.prototype.exec = function (backoffTimer, throttleTimeSlot) {
        var _this = this;
        if (backoffTimer === void 0) { backoffTimer = randomExponentialBackoffTimer; }
        if (throttleTimeSlot === void 0) { throttleTimeSlot = 1000; }
        this.logger.debug('starting batchWriteItem');
        var rBoT = backoffTimer();
        var backoffTime = 0;
        return this.execNextBatch().pipe(mergeMap(function (r) {
            if (!r.capacityExceeded) {
                rBoT = backoffTimer();
                backoffTime = 0;
            }
            else {
                backoffTime = rBoT.next().value * throttleTimeSlot;
                _this.logger.info("wait " + backoffTime + " ms until next request", { backoffTime: backoffTime });
            }
            return of(r).pipe(delay(backoffTime));
        }), mergeMap(function (r) {
            if (r.remainingItems > 0) {
                return _this.exec();
            }
            else {
                return of();
            }
        }));
    };
    return BatchWriteSingleTableRequest;
}());
export { BatchWriteSingleTableRequest };
//# sourceMappingURL=batch-write-single-table.request.js.map