"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NoAuthenticationProvider = exports.BasicAuthenticationProvider = exports.JwtAuthenticationProvider = exports.EnsembleAuthenticationProvider = void 0;
const EnsembleAuthService_1 = require("./EnsembleAuthService");
const JwtBridgedAuthService_1 = require("./JwtBridgedAuthService");
const NoAuthService_1 = require("./NoAuthService");
const BasicAuthService_1 = require("./BasicAuthService");
const JwtAuthService_1 = require("./JwtAuthService");
class EnsembleAuthenticationProvider {
    constructor(authApi, username, password, jwtTimeout = 3600, jwtAuth, basicAuth, thirdPartyTokens = {}) {
        this.authApi = authApi;
        this.username = username;
        this.password = password;
        this.jwtTimeout = jwtTimeout;
        this.jwtAuth = jwtAuth !== null && jwtAuth !== void 0 ? jwtAuth : new JwtBridgedAuthService_1.JwtBridgedAuthService(this.authApi, this.username, this.password, thirdPartyTokens, undefined);
        this.basicAuth = basicAuth !== null && basicAuth !== void 0 ? basicAuth : new BasicAuthService_1.BasicAuthService(this.username, this.password);
    }
    getIcureTokens() {
        return this.jwtAuth.getIcureTokens();
    }
    getAuthService() {
        // If the jwtAuth is in an error state, it instantiates a new one,
        // but it will not use it until the suspension ends
        if (this.jwtAuth.isInErrorState()) {
            console.warn('Error state in JWT, I will skip it');
            this.jwtAuth = new JwtBridgedAuthService_1.JwtBridgedAuthService(this.authApi, this.username, this.password, {}, undefined);
            this.suspensionEnd = new Date(new Date().getTime() + this.jwtTimeout * 1000);
        }
        return !!this.suspensionEnd && new Date() <= this.suspensionEnd
            ? new EnsembleAuthService_1.EnsembleAuthService(null, new NoAuthService_1.NoAuthService(), this.basicAuth)
            : new EnsembleAuthService_1.EnsembleAuthService(this.jwtAuth, new NoAuthService_1.NoAuthService(), this.basicAuth);
    }
    switchGroup(newGroupId, matches) {
        return __awaiter(this, void 0, void 0, function* () {
            const switchInfo = yield switchJwtAuth(this.authApi, this.jwtAuth, this.username, this.password, newGroupId, matches);
            return new EnsembleAuthenticationProvider(this.authApi, switchInfo.loginForGroup, this.password, this.jwtTimeout, switchInfo.switchedJwtAuth, new BasicAuthService_1.BasicAuthService(switchInfo.loginForGroup, this.password));
        });
    }
}
exports.EnsembleAuthenticationProvider = EnsembleAuthenticationProvider;
class JwtAuthenticationProvider {
    getIcureTokens() {
        return this.jwtAuth.getIcureTokens();
    }
    /**
     * @internal
     * @param authApi
     * @param username
     * @param password
     * @param jwtAuth
     * @param icureToken
     */
    constructor(authApi, username, password, jwtAuth, icureToken) {
        this.authApi = authApi;
        this.username = username;
        this.password = password;
        const composedAuth = jwtAuth !== null && jwtAuth !== void 0 ? jwtAuth : (!!username && !!password
            ? new JwtBridgedAuthService_1.JwtBridgedAuthService(authApi, username, password, {}, icureToken ? { authJwt: icureToken.token, refreshJwt: icureToken.refreshToken } : undefined)
            : icureToken
                ? new JwtAuthService_1.JwtAuthService(authApi, { authJwt: icureToken.token, refreshJwt: icureToken.refreshToken })
                : undefined);
        if (!composedAuth) {
            throw new Error('No authentication method provided');
        }
        this.jwtAuth = composedAuth;
    }
    getAuthService() {
        return this.jwtAuth;
    }
    switchGroup(newGroupId, matches) {
        return __awaiter(this, void 0, void 0, function* () {
            const switchInfo = yield switchJwtAuth(this.authApi, this.jwtAuth, this.username, this.password, newGroupId, matches);
            return new JwtAuthenticationProvider(this.authApi, switchInfo.loginForGroup, this.password, switchInfo.switchedJwtAuth);
        });
    }
}
exports.JwtAuthenticationProvider = JwtAuthenticationProvider;
class BasicAuthenticationProvider {
    getIcureTokens() {
        return Promise.resolve();
    }
    constructor(username, password) {
        this.username = username;
        this.password = password;
    }
    getAuthService() {
        return new BasicAuthService_1.BasicAuthService(this.username, this.password);
    }
    switchGroup(newGroupId, matches) {
        return __awaiter(this, void 0, void 0, function* () {
            return Promise.resolve(new BasicAuthenticationProvider(loginForGroup(newGroupId, matches), this.password));
        });
    }
}
exports.BasicAuthenticationProvider = BasicAuthenticationProvider;
class NoAuthenticationProvider {
    getAuthService() {
        return new NoAuthService_1.NoAuthService();
    }
    getIcureTokens() {
        return Promise.resolve();
    }
    switchGroup(newGroupId, matches) {
        return __awaiter(this, void 0, void 0, function* () {
            return Promise.resolve(new NoAuthenticationProvider());
        });
    }
}
exports.NoAuthenticationProvider = NoAuthenticationProvider;
/**
 * @internal
 */
function loginForGroup(groupId, matches) {
    const matchForGroup = matches.find((x) => x.groupId === groupId);
    if (!(matchForGroup === null || matchForGroup === void 0 ? void 0 : matchForGroup.userId)) {
        throw new Error(`Can't switch to group ${groupId} for the current user.`);
    }
    return `${groupId}/${matchForGroup.userId}`;
}
/**
 * @internal
 * Creates a jwtAuth from an existing one in order to switch group
 */
function switchJwtAuth(authApi, jwtAuth, username, password, newGroupId, matches) {
    return __awaiter(this, void 0, void 0, function* () {
        const refreshToken = jwtAuth.isInErrorState() ? undefined : yield jwtAuth.refreshToken;
        const switchedJwtInfo = refreshToken ? yield authApi.switchGroup(refreshToken, newGroupId).catch(() => undefined) : undefined;
        const updatedLogin = loginForGroup(newGroupId, matches);
        const switchedJwtAuth = !!username && !!password
            ? new JwtBridgedAuthService_1.JwtBridgedAuthService(authApi, updatedLogin, password, {}, (switchedJwtInfo === null || switchedJwtInfo === void 0 ? void 0 : switchedJwtInfo.token) && (switchedJwtInfo === null || switchedJwtInfo === void 0 ? void 0 : switchedJwtInfo.refreshToken)
                ? { authJwt: switchedJwtInfo.token, refreshJwt: switchedJwtInfo.refreshToken }
                : undefined)
            : new JwtAuthService_1.JwtAuthService(authApi, (switchedJwtInfo === null || switchedJwtInfo === void 0 ? void 0 : switchedJwtInfo.token) && (switchedJwtInfo === null || switchedJwtInfo === void 0 ? void 0 : switchedJwtInfo.refreshToken)
                ? { authJwt: switchedJwtInfo.token, refreshJwt: switchedJwtInfo.refreshToken }
                : undefined);
        return { loginForGroup: updatedLogin, switchedJwtAuth };
    });
}
//# sourceMappingURL=AuthenticationProvider.js.map