import { __awaiter } from 'tslib';
import { createTransport } from '@sentry/core';
import { logger } from '@sentry/utils';
import { net } from 'electron';
import { join } from 'path';
import { getSentryCachePath } from '../fs.js';
import { createElectronNetRequestExecutor } from './electron-net.js';
import { PersistedRequestQueue } from './queue.js';

const START_DELAY = 5000;
const MAX_DELAY = 2000000000;
/** Returns true is there's a chance we're online */
function maybeOnline() {
    return !('online' in net) || net.online === true;
}
function defaultBeforeSend(_) {
    return maybeOnline() ? 'send' : 'queue';
}
function isRateLimited(result) {
    return !!(result.headers && 'x-sentry-rate-limits' in result.headers);
}
/**
 * Creates a Transport that uses Electrons net module to send events to Sentry. When they fail to send they are
 * persisted to disk and sent later
 */
function makeElectronOfflineTransport(options) {
    const netMakeRequest = createElectronNetRequestExecutor(options.url, options.headers || {});
    const queue = new PersistedRequestQueue(join(getSentryCachePath(), 'queue'), options.maxQueueAgeDays, options.maxQueueCount);
    const beforeSend = options.beforeSend || defaultBeforeSend;
    let retryDelay = START_DELAY;
    let lastQueueLength = -1;
    function queueLengthChanged(queuedEvents) {
        if (options.queuedLengthChanged && queuedEvents !== lastQueueLength) {
            lastQueueLength = queuedEvents;
            options.queuedLengthChanged(queuedEvents);
        }
    }
    function flushQueue() {
        queue
            .pop()
            .then((found) => {
            if (found) {
                // We have pendingCount plus found.request
                queueLengthChanged(found.pendingCount + 1);
                logger.log('Found a request in the queue');
                makeRequest(found.request).catch((e) => logger.error(e));
            }
            else {
                queueLengthChanged(0);
            }
        })
            .catch((e) => logger.error(e));
    }
    function queueRequest(request) {
        return __awaiter(this, void 0, void 0, function* () {
            logger.log('Queuing request');
            queueLengthChanged(yield queue.add(request));
            setTimeout(() => {
                flushQueue();
            }, retryDelay);
            retryDelay *= 3;
            // If the delay is bigger than 2^31 (max signed 32-bit int), setTimeout throws
            // an error and falls back to 1 which can cause a huge number of requests.
            if (retryDelay > MAX_DELAY) {
                retryDelay = MAX_DELAY;
            }
            return {};
        });
    }
    function makeRequest(request) {
        return __awaiter(this, void 0, void 0, function* () {
            let action = beforeSend(request);
            if (action instanceof Promise) {
                action = yield action;
            }
            if (action === 'send') {
                try {
                    const result = yield netMakeRequest(request);
                    if (!isRateLimited(result)) {
                        logger.log('Successfully sent');
                        // Reset the retry delay
                        retryDelay = START_DELAY;
                        // We were successful so check the queue
                        flushQueue();
                        return result;
                    }
                    else {
                        logger.log('Rate limited', result.headers);
                    }
                }
                catch (error) {
                    logger.log('Error sending:', error);
                }
                action = 'queue';
            }
            if (action == 'queue') {
                return queueRequest(request);
            }
            logger.log('Dropping request');
            return {};
        });
    }
    flushQueue();
    return createTransport(options, makeRequest);
}

export { makeElectronOfflineTransport };
//# sourceMappingURL=electron-offline-net.js.map
