import DatabaseService from "./DatabaseService";
import Model from "../../Models/DatabaseModels/StatusPagePrivateUserSession";
import ObjectID from "../../Types/ObjectID";
import HashedString from "../../Types/HashedString";
import { EncryptionSecret } from "../EnvironmentConfig";
import OneUptimeDate from "../../Types/Date";
import Text from "../../Types/Text";
import logger from "../Utils/Logger";
import BadDataException from "../../Types/Exception/BadDataException";
export class Service extends DatabaseService {
    constructor() {
        super(Model);
    }
    async createSession(options) {
        const refreshToken = options.refreshToken || Service.generateRefreshToken();
        const refreshTokenExpiresAt = options.refreshTokenExpiresAt || Service.getRefreshTokenExpiry();
        const session = this.buildSessionModel(options, {
            refreshToken,
            refreshTokenExpiresAt,
        });
        try {
            const createdSession = await this.create({
                data: session,
                props: {
                    isRoot: true,
                },
            });
            return {
                session: createdSession,
                refreshToken,
                refreshTokenExpiresAt,
            };
        }
        catch (error) {
            throw error;
        }
    }
    async findActiveSessionByRefreshToken(refreshToken) {
        const hashedValue = await HashedString.hashValue(refreshToken, EncryptionSecret);
        const session = await this.findOneBy({
            query: {
                refreshToken: new HashedString(hashedValue, true),
                isRevoked: false,
            },
            select: {
                _id: true,
                projectId: true,
                statusPageId: true,
                statusPagePrivateUserId: true,
                refreshTokenExpiresAt: true,
                lastActiveAt: true,
                additionalInfo: true,
                deviceName: true,
                deviceType: true,
                deviceOS: true,
                deviceBrowser: true,
                ipAddress: true,
                userAgent: true,
                isRevoked: true,
            },
            props: {
                isRoot: true,
            },
        });
        if (!session) {
            return null;
        }
        if (!session.refreshTokenExpiresAt ||
            OneUptimeDate.hasExpired(session.refreshTokenExpiresAt)) {
            return null;
        }
        return session;
    }
    async renewSessionWithNewRefreshToken(options) {
        const refreshToken = Service.generateRefreshToken();
        const refreshTokenExpiresAt = options.refreshTokenExpiresAt || Service.getRefreshTokenExpiry();
        const updatePayload = {
            refreshToken: HashedString.fromString(refreshToken),
            refreshTokenExpiresAt: refreshTokenExpiresAt,
            lastActiveAt: OneUptimeDate.getCurrentDate(),
            isRevoked: false,
        };
        const ipAddress = Text.truncate(options.ipAddress, Service.SHORT_TEXT_LIMIT);
        if (ipAddress) {
            updatePayload.ipAddress = ipAddress;
        }
        if (options.userAgent) {
            updatePayload.userAgent = options.userAgent;
        }
        const deviceName = Text.truncate(options.deviceName, Service.SHORT_TEXT_LIMIT);
        if (deviceName) {
            updatePayload.deviceName = deviceName;
        }
        const deviceType = Text.truncate(options.deviceType, Service.SHORT_TEXT_LIMIT);
        if (deviceType) {
            updatePayload.deviceType = deviceType;
        }
        const deviceOS = Text.truncate(options.deviceOS, Service.SHORT_TEXT_LIMIT);
        if (deviceOS) {
            updatePayload.deviceOS = deviceOS;
        }
        const deviceBrowser = Text.truncate(options.deviceBrowser, Service.SHORT_TEXT_LIMIT);
        if (deviceBrowser) {
            updatePayload.deviceBrowser = deviceBrowser;
        }
        if (options.additionalInfo || options.session.additionalInfo) {
            updatePayload.additionalInfo = Object.assign(Object.assign({}, (options.session.additionalInfo || {})), (options.additionalInfo || {}));
        }
        const updatedSession = await this.updateOneByIdAndFetch({
            id: options.session.id,
            data: updatePayload,
            props: {
                isRoot: true,
            },
        });
        if (!updatedSession) {
            throw new BadDataException("Unable to renew status page user session");
        }
        return {
            session: updatedSession,
            refreshToken,
            refreshTokenExpiresAt,
        };
    }
    async touchSession(sessionId, options) {
        const updatePayload = {
            lastActiveAt: OneUptimeDate.getCurrentDate(),
        };
        const ipAddress = Text.truncate(options.ipAddress, Service.SHORT_TEXT_LIMIT);
        if (ipAddress) {
            updatePayload.ipAddress = ipAddress;
        }
        if (options.userAgent) {
            updatePayload.userAgent = options.userAgent;
        }
        try {
            await this.updateOneById({
                id: sessionId,
                data: updatePayload,
                props: {
                    isRoot: true,
                },
            });
        }
        catch (err) {
            logger.warn(`Failed to update status page session activity for session ${sessionId.toString()}: ${err.message}`);
        }
    }
    async revokeSessionById(sessionId, options) {
        var _a;
        await this.updateOneById({
            id: sessionId,
            data: {
                isRevoked: true,
                revokedAt: OneUptimeDate.getCurrentDate(),
                revokedReason: (_a = options === null || options === void 0 ? void 0 : options.reason) !== null && _a !== void 0 ? _a : null,
            },
            props: {
                isRoot: true,
            },
        });
    }
    async revokeSessionByRefreshToken(refreshToken, options) {
        const session = await this.findActiveSessionByRefreshToken(refreshToken);
        if (!session || !session.id) {
            return;
        }
        await this.revokeSessionById(session.id, options);
    }
    buildSessionModel(options, tokenMeta) {
        const session = new Model();
        session.projectId = options.projectId;
        session.statusPageId = options.statusPageId;
        session.statusPagePrivateUserId = options.statusPagePrivateUserId;
        session.refreshToken = HashedString.fromString(tokenMeta.refreshToken);
        session.refreshTokenExpiresAt = tokenMeta.refreshTokenExpiresAt;
        session.lastActiveAt = OneUptimeDate.getCurrentDate();
        if (options.userAgent) {
            session.userAgent = options.userAgent;
        }
        const deviceName = Text.truncate(options.deviceName, Service.SHORT_TEXT_LIMIT);
        if (deviceName) {
            session.deviceName = deviceName;
        }
        const deviceType = Text.truncate(options.deviceType, Service.SHORT_TEXT_LIMIT);
        if (deviceType) {
            session.deviceType = deviceType;
        }
        const deviceOS = Text.truncate(options.deviceOS, Service.SHORT_TEXT_LIMIT);
        if (deviceOS) {
            session.deviceOS = deviceOS;
        }
        const deviceBrowser = Text.truncate(options.deviceBrowser, Service.SHORT_TEXT_LIMIT);
        if (deviceBrowser) {
            session.deviceBrowser = deviceBrowser;
        }
        const ipAddress = Text.truncate(options.ipAddress, Service.SHORT_TEXT_LIMIT);
        if (ipAddress) {
            session.ipAddress = ipAddress;
        }
        session.additionalInfo = Object.assign({}, (options.additionalInfo || {}));
        return session;
    }
    static generateRefreshToken() {
        return ObjectID.generate().toString();
    }
    static getRefreshTokenExpiry() {
        return OneUptimeDate.getSomeDaysAfter(Service.DEFAULT_REFRESH_TOKEN_TTL_DAYS);
    }
}
Service.DEFAULT_REFRESH_TOKEN_TTL_DAYS = 30;
Service.SHORT_TEXT_LIMIT = 100;
export default new Service();
//# sourceMappingURL=StatusPagePrivateUserSessionService.js.map