const core = require('@sentry/core');
const fs = require('fs');
const path = require('path');
const electronNormalize = require('../electron-normalize.js');
const store = require('../store.js');

const MILLISECONDS_PER_DAY = 86400000;
function isOutdated(request, maxAgeDays) {
    const cutOff = Date.now() - MILLISECONDS_PER_DAY * maxAgeDays;
    return (request?.date?.getTime() || 0) < cutOff;
}
function getSentAtFromEnvelope(envelope) {
    const header = envelope[0];
    if (typeof header.sent_at === 'string') {
        return new Date(header.sent_at);
    }
    return undefined;
}
/**
 * Creates a new offline store.
 */
function createOfflineStore(userOptions) {
    function log(...args) {
        core.debug.log('[Offline Store]:', ...args);
    }
    const options = {
        maxAgeDays: userOptions.maxAgeDays || 30,
        maxQueueSize: userOptions.maxQueueSize || 30,
        queuePath: userOptions.queuePath || path.join(electronNormalize.getSentryCachePath(), 'queue'),
    };
    const queue = new store.Store(options.queuePath, 'queue-v2', []);
    function removeBody(id) {
        fs.promises.unlink(path.join(options.queuePath, id)).catch(() => {
            // ignore
        });
    }
    function removeStaleRequests(queue) {
        while (queue[0] && isOutdated(queue[0], options.maxAgeDays)) {
            const removed = queue.shift();
            log('Removing stale envelope', removed);
            removeBody(removed.id);
        }
    }
    async function insert(env, which, previousDate) {
        log(`${which}ing envelope into offline storage`);
        const id = core.uuid4();
        try {
            const data = core.serializeEnvelope(env);
            await fs.promises.mkdir(options.queuePath, { recursive: true });
            await fs.promises.writeFile(path.join(options.queuePath, id), data);
        }
        catch (e) {
            log('Failed to save', e);
        }
        await queue.update((queue) => {
            if (which === 'push') {
                removeStaleRequests(queue);
                if (queue.length >= options.maxQueueSize) {
                    removeBody(id);
                    return queue;
                }
            }
            queue[which]({ id, date: previousDate || getSentAtFromEnvelope(env) || new Date() });
            return queue;
        });
    }
    // We store the timestamp for the last envelope that was shifted out so that if it gets unshifted back in
    // it can keep its original date
    let lastShiftedDate;
    return {
        push: async (env) => {
            await insert(env, 'push');
        },
        unshift: async (env) => {
            await insert(env, 'unshift', lastShiftedDate);
        },
        shift: async () => {
            log('Popping envelope from offline storage');
            let request;
            await queue.update((queue) => {
                removeStaleRequests(queue);
                request = queue.shift();
                return queue;
            });
            if (request) {
                try {
                    const data = await fs.promises.readFile(path.join(options.queuePath, request.id));
                    removeBody(request.id);
                    lastShiftedDate = request.date;
                    return core.parseEnvelope(data);
                }
                catch (e) {
                    log('Failed to read', e);
                }
            }
            return undefined;
        },
    };
}

exports.createOfflineStore = createOfflineStore;
//# sourceMappingURL=offline-store.js.map
