import { __assign, __awaiter, __generator } from "tslib";
import { BaseTransport } from '@amplitude/analytics-core';
import { Status } from '@amplitude/analytics-types';
import { getCurrentUrl, getServerUrl } from './helpers';
import { MAX_RETRIES_EXCEEDED_MESSAGE, MISSING_API_KEY_MESSAGE, MISSING_DEVICE_ID_MESSAGE, UNEXPECTED_ERROR_MESSAGE, UNEXPECTED_NETWORK_ERROR_MESSAGE, } from './messages';
import { VERSION } from './version';
import { MAX_URL_LENGTH, KB_SIZE } from './constants';
var SessionReplayTrackDestination = /** @class */ (function () {
    function SessionReplayTrackDestination(_a) {
        var trackServerUrl = _a.trackServerUrl, loggerProvider = _a.loggerProvider, payloadBatcher = _a.payloadBatcher;
        this.storageKey = '';
        this.retryTimeout = 1000;
        this.scheduled = null;
        this.queue = [];
        this.loggerProvider = loggerProvider;
        this.payloadBatcher = payloadBatcher ? payloadBatcher : function (payload) { return payload; };
        this.trackServerUrl = trackServerUrl;
    }
    SessionReplayTrackDestination.prototype.sendEventsList = function (destinationData) {
        this.addToQueue(__assign(__assign({}, destinationData), { attempts: 0, timeout: 0 }));
    };
    SessionReplayTrackDestination.prototype.addToQueue = function () {
        var _this = this;
        var list = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            list[_i] = arguments[_i];
        }
        var tryable = list.filter(function (context) {
            if (context.attempts < (context.flushMaxRetries || 0)) {
                context.attempts += 1;
                return true;
            }
            _this.completeRequest({
                context: context,
                err: MAX_RETRIES_EXCEEDED_MESSAGE,
            });
            return false;
        });
        tryable.forEach(function (context) {
            _this.queue = _this.queue.concat(context);
            if (context.timeout === 0) {
                _this.schedule(0);
                return;
            }
            setTimeout(function () {
                context.timeout = 0;
                _this.schedule(0);
            }, context.timeout);
        });
    };
    SessionReplayTrackDestination.prototype.schedule = function (timeout) {
        var _this = this;
        if (this.scheduled)
            return;
        this.scheduled = setTimeout(function () {
            void _this.flush(true).then(function () {
                if (_this.queue.length > 0) {
                    _this.schedule(timeout);
                }
            });
        }, timeout);
    };
    SessionReplayTrackDestination.prototype.flush = function (useRetry) {
        if (useRetry === void 0) { useRetry = false; }
        return __awaiter(this, void 0, void 0, function () {
            var list, later;
            var _this = this;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        list = [];
                        later = [];
                        this.queue.forEach(function (context) { return (context.timeout === 0 ? list.push(context) : later.push(context)); });
                        this.queue = later;
                        if (this.scheduled) {
                            clearTimeout(this.scheduled);
                            this.scheduled = null;
                        }
                        return [4 /*yield*/, Promise.all(list.map(function (context) { return _this.send(context, useRetry); }))];
                    case 1:
                        _a.sent();
                        return [2 /*return*/];
                }
            });
        });
    };
    SessionReplayTrackDestination.prototype.send = function (context, useRetry) {
        var _a, _b;
        if (useRetry === void 0) { useRetry = true; }
        return __awaiter(this, void 0, void 0, function () {
            var apiKey, deviceId, url, version, sampleRate, urlParams, sessionReplayLibrary, payload, options, serverUrl, res, responseBody, e_1;
            return __generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        apiKey = context.apiKey;
                        if (!apiKey) {
                            return [2 /*return*/, this.completeRequest({ context: context, err: MISSING_API_KEY_MESSAGE })];
                        }
                        deviceId = context.deviceId;
                        if (!deviceId) {
                            return [2 /*return*/, this.completeRequest({ context: context, err: MISSING_DEVICE_ID_MESSAGE })];
                        }
                        url = getCurrentUrl();
                        version = VERSION;
                        sampleRate = context.sampleRate;
                        urlParams = new URLSearchParams({
                            device_id: deviceId,
                            session_id: "".concat(context.sessionId),
                            type: "".concat(context.type),
                        });
                        sessionReplayLibrary = "".concat(((_a = context.version) === null || _a === void 0 ? void 0 : _a.type) || 'standalone', "/").concat(((_b = context.version) === null || _b === void 0 ? void 0 : _b.version) || version);
                        payload = this.payloadBatcher({
                            version: 1,
                            events: context.events,
                        });
                        if (payload.events.length === 0) {
                            this.completeRequest({ context: context });
                            return [2 /*return*/];
                        }
                        _c.label = 1;
                    case 1:
                        _c.trys.push([1, 3, , 4]);
                        options = {
                            headers: {
                                'Content-Type': 'application/json',
                                Accept: '*/*',
                                Authorization: "Bearer ".concat(apiKey),
                                'X-Client-Version': version,
                                'X-Client-Library': sessionReplayLibrary,
                                'X-Client-Url': url.substring(0, MAX_URL_LENGTH),
                                'X-Client-Sample-Rate': "".concat(sampleRate),
                            },
                            body: JSON.stringify(payload),
                            method: 'POST',
                        };
                        serverUrl = "".concat(getServerUrl(context.serverZone, this.trackServerUrl), "?").concat(urlParams.toString());
                        return [4 /*yield*/, fetch(serverUrl, options)];
                    case 2:
                        res = _c.sent();
                        if (res === null) {
                            this.completeRequest({ context: context, err: UNEXPECTED_ERROR_MESSAGE });
                            return [2 /*return*/];
                        }
                        if (!useRetry) {
                            responseBody = '';
                            try {
                                responseBody = JSON.stringify(res.body, null, 2);
                            }
                            catch (_d) {
                                // to avoid crash, but don't care about the error, add comment to avoid empty block lint error
                            }
                            this.completeRequest({ context: context, success: "".concat(res.status, ": ").concat(responseBody) });
                        }
                        else {
                            this.handleReponse(res.status, context);
                        }
                        return [3 /*break*/, 4];
                    case 3:
                        e_1 = _c.sent();
                        this.completeRequest({ context: context, err: e_1 });
                        return [3 /*break*/, 4];
                    case 4: return [2 /*return*/];
                }
            });
        });
    };
    SessionReplayTrackDestination.prototype.handleReponse = function (status, context) {
        var parsedStatus = new BaseTransport().buildStatus(status);
        switch (parsedStatus) {
            case Status.Success:
                this.handleSuccessResponse(context);
                break;
            case Status.Failed:
                this.handleOtherResponse(context);
                break;
            default:
                this.completeRequest({ context: context, err: UNEXPECTED_NETWORK_ERROR_MESSAGE });
        }
    };
    SessionReplayTrackDestination.prototype.handleSuccessResponse = function (context) {
        var sizeOfEventsList = Math.round(new Blob(context.events).size / KB_SIZE);
        this.completeRequest({
            context: context,
            success: "Session replay event batch tracked successfully for session id ".concat(context.sessionId, ", size of events: ").concat(sizeOfEventsList, " KB"),
        });
    };
    SessionReplayTrackDestination.prototype.handleOtherResponse = function (context) {
        this.addToQueue(__assign(__assign({}, context), { timeout: context.attempts * this.retryTimeout }));
    };
    SessionReplayTrackDestination.prototype.completeRequest = function (_a) {
        var context = _a.context, err = _a.err, success = _a.success;
        void context.onComplete();
        if (err) {
            this.loggerProvider.warn(err);
        }
        else if (success) {
            this.loggerProvider.log(success);
        }
    };
    return SessionReplayTrackDestination;
}());
export { SessionReplayTrackDestination };
//# sourceMappingURL=track-destination.js.map