import { __awaiter } from 'tslib';
import { startSession as startSession$1, captureSession, getCurrentScope, getClient, makeSession, updateSession, endSession as endSession$1 } from '@sentry/core';
import { flush } from '@sentry/node';
import { logger } from '@sentry/utils';
import { app } from 'electron';
import { getSentryCachePath } from './fs.js';
import { Store } from './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(getSentryCachePath(), 'session', undefined);
        previousSession = sessionStore.get();
    }
    return sessionStore;
}
let persistTimer;
/** Starts a session */
function startSession(sendOnCreate) {
    const session = startSession$1();
    if (sendOnCreate) {
        captureSession();
    }
    getSessionStore()
        .set(session)
        .catch(() => {
        // Does not throw
    });
    // Every PERSIST_INTERVAL, write the session to disk
    persistTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
        const currentSession = 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 __awaiter(this, void 0, void 0, function* () {
        // Once the session had ended there is no point persisting it
        if (persistTimer) {
            clearInterval(persistTimer);
        }
        const session = getCurrentScope().getSession();
        if (session) {
            if (session.status === 'ok') {
                logger.log('Ending session');
                endSession$1();
            }
            else {
                logger.log('Session was already ended');
            }
        }
        else {
            logger.log('No session');
        }
        yield getSessionStore().clear();
        yield flush(2000);
    });
}
/** Determines if a Date is likely to have occurred in the previous uncompleted session */
function unreportedDuringLastSession(crashDate) {
    return __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 __awaiter(this, void 0, void 0, function* () {
        const client = 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';
            logger.log(`Found previous ${status} session`);
            const sesh = makeSession(previous);
            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);
    }
    logger.log('Session Crashed');
    const session = getCurrentScope().getSession();
    if (!session) {
        logger.log('No session to update');
        return;
    }
    if (session.status === 'ok') {
        logger.log('Setting session as crashed');
        const errors = session.errors + 1;
        updateSession(session, { status: 'crashed', errors });
    }
    else {
        logger.log('Session already ended');
    }
    captureSession();
}
/** Sets the current session as ANR */
function sessionAnr() {
    // stop persisting session
    if (persistTimer) {
        clearInterval(persistTimer);
    }
    const session = getCurrentScope().getSession();
    if (!session) {
        return;
    }
    if (session.status === 'ok') {
        logger.log('Setting session as abnormal ANR');
        updateSession(session, { status: 'abnormal', abnormal_mechanism: 'anr_foreground' });
        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
    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.
        app.removeListener('will-quit', exitHandler);
        app.on('will-quit', exitHandler);
    });
}
/** Handles the exit */
const exitHandler = (event) => __awaiter(void 0, void 0, void 0, function* () {
    if (event.defaultPrevented) {
        return;
    }
    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
        logger.warn('[Session] Error ending session:', e);
    }
    app.exit();
});

export { checkPreviousSession, endSession, endSessionOnExit, sessionAnr, sessionCrashed, startSession, unreportedDuringLastSession };
//# sourceMappingURL=sessions.js.map
