"use strict";
/*
 *  Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *  SPDX-License-Identifier: Apache-2.0
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const workbench_core_base_1 = require("@aws/workbench-core-base");
const jwt_decode_1 = __importDefault(require("jwt-decode"));
const lodash_1 = __importDefault(require("lodash"));
const clientSession_1 = __importDefault(require("./clientSession"));
const settings_1 = __importDefault(require("./utils/settings"));
class Setup {
    constructor() {
        this._sessions = [];
        this._defaultAdminSession = undefined;
        // @ts-ignore
        this._settings = new settings_1.default(global['__settings__']);
        jest.retryTimes(1);
    }
    static getSetup() {
        return new Setup();
    }
    async createAnonymousSession(outputError) {
        const session = this._getClientSession(undefined, outputError);
        this._sessions.push(session);
        return session;
    }
    async createAdminSession() {
        throw new Error('Implement createAdminSession');
    }
    async getDefaultAdminSession(outputError) {
        if (this._defaultAdminSession) {
            const decodedIdToken = (0, jwt_decode_1.default)(this._defaultAdminSession.accessToken);
            const expiresAt = lodash_1.default.get(decodedIdToken, 'exp', 0) * 1000;
            // Assume the default admin session is shared between all test cases in a given test suite (ie. test file),
            // so it has to stay active throughout the test suite duration.
            // Therefore the buffer time (in minutes) should be the longest time taken by any single test suite
            // If the current token has less than the buffer minutes remaining, we create a new one.
            const bufferInMinutes = 25;
            const tokenExpired = (expiresAt - Date.now()) / 60 / 1000 < bufferInMinutes;
            if (!tokenExpired) {
                return this._defaultAdminSession;
            }
        }
        const userPoolId = this._settings.get('cognitoUserPoolId');
        const clientId = this._settings.get('cognitoUserPoolClientId');
        const rootUserNameParamStorePath = this._settings.get('rootUserNameParamStorePath');
        const rootPasswordParamStorePath = this._settings.get('rootPasswordParamStorePath');
        const awsRegion = this._settings.get('awsRegion');
        const secretsService = new workbench_core_base_1.SecretsService(new workbench_core_base_1.AwsService({ region: awsRegion }).clients.ssm);
        await this._loadSecrets(secretsService);
        const cognitoTokenService = new workbench_core_base_1.CognitoTokenService(awsRegion, secretsService);
        const { accessToken } = await cognitoTokenService.generateCognitoToken({
            userPoolId,
            clientId,
            rootUserNameParamStorePath,
            rootPasswordParamStorePath
        });
        const session = this._getClientSession(accessToken, outputError);
        this._sessions.push(session);
        this._defaultAdminSession = session;
        return this._defaultAdminSession;
    }
    async getSessionForUserType(userType, outputError) {
        const userNameParamStorePath = this._settings.get(`${userType}UserNameParamStorePath`);
        const userPasswordParamStorePath = this._settings.get(`${userType}PasswordParamStorePath`);
        const awsRegion = this._settings.get('awsRegion');
        const secretsService = new workbench_core_base_1.SecretsService(new workbench_core_base_1.AwsService({ region: awsRegion }).clients.ssm);
        const userName = await secretsService.getSecret(userNameParamStorePath);
        const password = await secretsService.getSecret(userPasswordParamStorePath);
        return this.getSessionForUser(userName, password, outputError);
    }
    async getSessionForUser(userName, password, outputError) {
        const accessToken = await this._getCognitoTokenForUser(userName, password);
        const session = this._getClientSession(accessToken, outputError);
        this._sessions.push(session);
        return session;
    }
    async _getCognitoTokenForUser(userName, password) {
        const userPoolId = this._settings.get('cognitoUserPoolId');
        const clientId = this._settings.get('cognitoUserPoolClientId');
        const awsRegion = this._settings.get('awsRegion');
        const secretsService = new workbench_core_base_1.SecretsService(new workbench_core_base_1.AwsService({ region: awsRegion }).clients.ssm);
        await this._loadSecrets(secretsService);
        const cognitoTokenService = new workbench_core_base_1.CognitoTokenService(awsRegion, secretsService);
        const { accessToken } = await cognitoTokenService.generateCognitoTokenWithCredentials(userPoolId, clientId, userName, password, 'USER');
        return accessToken;
    }
    getStackName() {
        return `rsw-${process.env.STAGE}-${this._settings.get('awsRegionShortName')}`;
    }
    getMainAwsClient() {
        return new workbench_core_base_1.AwsService({
            region: this._settings.get('awsRegion'),
            ddbTableName: this.getStackName() // table name is same as stack name
        });
    }
    async cleanup() {
        // We need to reverse the order of the queue before we cleanup the sessions
        const sessions = lodash_1.default.reverse(lodash_1.default.slice(this._sessions));
        for (const session of sessions) {
            try {
                await session.cleanup();
            }
            catch (error) {
                console.error(error);
            }
        }
        this._sessions = []; // This way if the cleanup() method is called again, we don't need to cleanup again
    }
    getSettings() {
        return this._settings;
    }
    _getClientSession(accessToken, outputError) {
        return new clientSession_1.default(this, accessToken, outputError);
    }
    async _loadSecrets(secretsService) {
        if (this._settings.optional('awsAccountIdParamStorePath', undefined) === undefined) {
            return;
        }
        const [awsAccountId] = await Promise.all([
            secretsService.getSecret(this._settings.get('awsAccountIdParamStorePath'))
        ]);
        this._settings.set('awsAccountId', awsAccountId);
    }
}
exports.default = Setup;
//# sourceMappingURL=setup.js.map