const tslib = require('tslib');
const core = require('@sentry/core');
const node = require('@sentry/node');
const utils = require('@sentry/utils');
const electron = require('electron');
const fs = require('./fs.js');
const store = require('./store.js');

const PERSIST_INTERVAL_MS = 60000;
/** Stores the app session in case of termination due to main process crash or app killed */
let sessionStore;
/** Previous session if it did not exit cleanly */
let previousSession;
function getSessionStore() {
    if (!sessionStore) {
        sessionStore = new store.Store(fs.getSentryCachePath(), 'session', undefined);
        previousSession = sessionStore.get();
    }
    return sessionStore;
}
let persistTimer;
/** Starts a session */
function startSession(sendOnCreate) {
    const session = core.startSession();
    if (sendOnCreate) {
        core.captureSession();
    }
    getSessionStore()
        .set(session)
        .catch(() => {
        // Does not throw
    });
    // Every PERSIST_INTERVAL, write the session to disk
    persistTimer = setInterval(() => tslib.__awaiter(this, void 0, void 0, function* () {
        const currentSession = core.getCurrentScope().getSession();
        // Only bother saving if it hasn't already ended
        if (currentSession && currentSession.status === 'ok') {
            yield getSessionStore().set(currentSession);
        }
    }), PERSIST_INTERVAL_MS);
}
/** Cleanly ends a session */
function endSession() {
    return tslib.__awaiter(this, void 0, void 0, function* () {
        // Once the session had ended there is no point persisting it
        if (persistTimer) {
            clearInterval(persistTimer);
        }
        const session = core.getCurrentScope().getSession();
        if (session) {
            if (session.status === 'ok') {
                utils.logger.log('Ending session');
                core.endSession();
            }
            else {
                utils.logger.log('Session was already ended');
            }
        }
        else {
            utils.logger.log('No session');
        }
        yield getSessionStore().clear();
        yield node.flush(2000);
    });
}
/** Determines if a Date is likely to have occurred in the previous uncompleted session */
function unreportedDuringLastSession(crashDate) {
    return tslib.__awaiter(this, void 0, void 0, function* () {
        if (!crashDate) {
            return false;
        }
        const previousSessionModified = yield getSessionStore().getModifiedDate();
        // There is no previous session
        if (previousSessionModified === undefined) {
            return false;
        }
        const previousSessionModifiedTime = previousSessionModified.getTime();
        const crashTime = crashDate.getTime();
        // Session could have run until modified time + persist interval
        const prevSessionEnd = previousSessionModifiedTime + PERSIST_INTERVAL_MS;
        // Event cannot have occurred before last persist time, We add a 2 second overlap to be sure
        const lastPersist = previousSessionModifiedTime - 2000;
        // If the crash occurred between the last persist and estimated end of session
        return crashTime > lastPersist && crashTime < prevSessionEnd;
    });
}
/** Checks if the previous session needs sending as crashed or abnormal  */
function checkPreviousSession(crashed) {
    var _a, _b;
    return tslib.__awaiter(this, void 0, void 0, function* () {
        const client = core.getClient();
        const previous = yield previousSession;
        if (previous && client) {
            // Ignore if the previous session is already ended
            if (previous.status !== 'ok') {
                previousSession = undefined;
                return;
            }
            const status = crashed ? 'crashed' : 'abnormal';
            utils.logger.log(`Found previous ${status} session`);
            const sesh = core.makeSession(previous);
            core.updateSession(sesh, {
                status,
                errors: (sesh.errors || 0) + 1,
                release: (_a = previous.attrs) === null || _a === void 0 ? void 0 : _a.release,
                environment: (_b = previous.attrs) === null || _b === void 0 ? void 0 : _b.environment,
            });
            yield client.sendSession(sesh);
            previousSession = undefined;
        }
    });
}
/** Sets the current session as crashed */
function sessionCrashed() {
    // stop persisting session
    if (persistTimer) {
        clearInterval(persistTimer);
    }
    utils.logger.log('Session Crashed');
    const session = core.getCurrentScope().getSession();
    if (!session) {
        utils.logger.log('No session to update');
        return;
    }
    if (session.status === 'ok') {
        utils.logger.log('Setting session as crashed');
        const errors = session.errors + 1;
        core.updateSession(session, { status: 'crashed', errors });
    }
    else {
        utils.logger.log('Session already ended');
    }
    core.captureSession();
}
/** Sets the current session as ANR */
function sessionAnr() {
    // stop persisting session
    if (persistTimer) {
        clearInterval(persistTimer);
    }
    const session = core.getCurrentScope().getSession();
    if (!session) {
        return;
    }
    if (session.status === 'ok') {
        utils.logger.log('Setting session as abnormal ANR');
        core.updateSession(session, { status: 'abnormal', abnormal_mechanism: 'anr_foreground' });
        core.captureSession();
    }
}
/**
 * End the current session on app exit
 */
function endSessionOnExit() {
    // 'before-quit' is always called before 'will-quit' so we listen there and ensure our 'will-quit' handler is still
    // the last listener
    electron.app.on('before-quit', () => {
        // We track the end of sessions via the 'will-quit' event which is the last event emitted before close.
        //
        // We need to be the last 'will-quit' listener so as not to interfere with any user defined listeners which may
        // call `event.preventDefault()` to abort the exit.
        electron.app.removeListener('will-quit', exitHandler);
        electron.app.on('will-quit', exitHandler);
    });
}
/** Handles the exit */
const exitHandler = (event) => tslib.__awaiter(void 0, void 0, void 0, function* () {
    if (event.defaultPrevented) {
        return;
    }
    utils.logger.log('[Session] Exit Handler');
    // Stop the exit so we have time to send the session
    event.preventDefault();
    try {
        // End the session
        yield endSession();
    }
    catch (e) {
        // Ignore and log any errors which would prevent app exit
        utils.logger.warn('[Session] Error ending session:', e);
    }
    electron.app.exit();
});

exports.checkPreviousSession = checkPreviousSession;
exports.endSession = endSession;
exports.endSessionOnExit = endSessionOnExit;
exports.sessionAnr = sessionAnr;
exports.sessionCrashed = sessionCrashed;
exports.startSession = startSession;
exports.unreportedDuringLastSession = unreportedDuringLastSession;
//# sourceMappingURL=sessions.js.map
