import { __awaiter } from 'tslib';
import { uuid4, logger } from '@sentry/utils';
import { join } from 'path';
import { writeFileAsync, readFileAsync, unlinkAsync } from '../fs.js';
import { BufferedWriteStore } from '../store.js';

const MILLISECONDS_PER_DAY = 86400000;
/** A request queue that is persisted to disk to survive app restarts */
class PersistedRequestQueue {
    constructor(_queuePath, _maxAgeDays = 30, _maxCount = 30) {
        this._queuePath = _queuePath;
        this._maxAgeDays = _maxAgeDays;
        this._maxCount = _maxCount;
        this._queue = new BufferedWriteStore(this._queuePath, 'queue', []);
    }
    /** Adds a request to the queue */
    add(request) {
        return __awaiter(this, void 0, void 0, function* () {
            const bodyPath = uuid4();
            let queuedEvents = 0;
            yield this._queue.update((queue) => {
                queue.push({
                    bodyPath,
                    date: request.date || new Date(),
                });
                while (queue.length > this._maxCount) {
                    const removed = queue.shift();
                    if (removed) {
                        this._removeBody(removed.bodyPath);
                    }
                }
                queuedEvents = queue.length;
                return queue;
            });
            try {
                yield writeFileAsync(join(this._queuePath, bodyPath), request.body);
            }
            catch (_) {
                //
            }
            return queuedEvents;
        });
    }
    /** Pops the oldest event from the queue */
    pop() {
        return __awaiter(this, void 0, void 0, function* () {
            let found;
            let pendingCount = 0;
            const cutOff = Date.now() - MILLISECONDS_PER_DAY * this._maxAgeDays;
            yield this._queue.update((queue) => {
                while ((found = queue.shift())) {
                    // We drop events created in v3 of the SDK or before the cut-off
                    if ('type' in found || found.date.getTime() < cutOff) {
                        // we're dropping this event so delete the body
                        this._removeBody(found.bodyPath);
                        found = undefined;
                    }
                    else {
                        pendingCount = queue.length;
                        break;
                    }
                }
                return queue;
            });
            if (found) {
                try {
                    const body = yield readFileAsync(join(this._queuePath, found.bodyPath));
                    this._removeBody(found.bodyPath);
                    return {
                        request: {
                            body,
                            date: found.date || new Date(),
                        },
                        pendingCount,
                    };
                }
                catch (e) {
                    logger.warn('Filed to read queued request body', e);
                }
            }
            return undefined;
        });
    }
    /** Removes the body of the request */
    _removeBody(bodyPath) {
        unlinkAsync(join(this._queuePath, bodyPath)).catch(() => {
            // ignore
        });
    }
}

export { PersistedRequestQueue };
//# sourceMappingURL=queue.js.map
