// The MIT License (MIT)
//
// Copyright (c) 2016-2024 Camptocamp SA
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import * as Sentry from '@sentry/browser';
import * as $ from 'jquery';
import user, { UserState, loginMessageRequired } from 'gmfapi/store/user';
import configuration from 'gmfapi/store/config';
let userTransformer = (user) => user;
/**
 * Method defined in the aim to be overridden.
 * @param fn The callback function to apply after login.
 */
export function setOnSuccessfulLoginFunction(fn) {
    userTransformer = fn;
}
export var RouteSuffix;
(function (RouteSuffix) {
    RouteSuffix["CHANGE_PASSWORD"] = "loginchangepassword";
    RouteSuffix["IS_LOGGED_IN"] = "loginuser";
    RouteSuffix["LOGIN"] = "login";
    RouteSuffix["LOGOUT"] = "logout";
    RouteSuffix["RESET_PASSWORD"] = "loginresetpassword";
})(RouteSuffix || (RouteSuffix = {}));
/**
 * An "authentication" service for a GeoMapFish application. Upon loading, it
 * launches a request to determine whether a user is currently logged in or
 * not.
 *
 * The possible API requests it supports, which are all self-explanatory, are:
 *
 * - changePassword
 * - login
 * - logout
 * - resetPassword
 */
export class AuthenticationService {
    constructor() {
        this.originalUrl = window.location.href;
        /**
         * The authentication url without trailing slash.
         * @private
         */
        this.baseUrl_ = null;
        /**
         * @private
         */
        this.user_ = null;
        user.getProperties().subscribe({
            next: (properties) => {
                this.user_ = properties;
            },
        });
        /**
         * Don't request a new user object from the back-end after
         * logging out if the logged-in user's role has this role.
         * @private
         */
        this.noReloadRole_ = null;
        configuration.getConfig().subscribe({
            next: (configuration) => {
                if (configuration) {
                    this.noReloadRole_ = configuration.gmfAuthenticationNoReloadRole;
                    this.baseUrl_ = configuration.authenticationBaseUrl
                        ? configuration.authenticationBaseUrl.replace(/\/$/, '')
                        : null;
                    if (this.baseUrl_) {
                        this.load_();
                    }
                }
            },
        });
        this.verifyConnection_ = window.setInterval(() => {
            this.checkConnection_();
        }, 60000);
    }
    /**
     * Check whether the user is connected or not like on load.
     * @private
     */
    checkConnection_() {
        if (this.user_.username && this.user_.is_password_changed !== false) {
            const url = `${this.baseUrl_}/${RouteSuffix.IS_LOGGED_IN}`;
            const options = { method: 'GET', credentials: 'include' };
            fetch(url, options)
                .then((resp) => resp.json())
                .then((data) => {
                if (this.user_.username !== data.username) {
                    this.handleDisconnection();
                }
            })
                .catch((err) => {
                throw new Error(`Error on connection check: ${err.statusText}`);
            });
        }
    }
    handleDisconnection() {
        const noReload = this.noReloadRole_ ? this.getRolesNames().includes(this.noReloadRole_) : false;
        this.resetUser(UserState.DISCONNECTED, noReload);
    }
    /**
     * Load the authentication service, which sends an async request to
     * determine whether the user is currently connected or not.
     * @private
     */
    load_() {
        const url = `${this.baseUrl_}/${RouteSuffix.IS_LOGGED_IN}`;
        const options = { method: 'GET', credentials: 'include' };
        fetch(url, options)
            .then((resp) => resp.json())
            .then((data) => this.checkUser_(data))
            .then((data) => this.handleLogin_(true, data), () => {
            throw new Error('Login fail.');
        });
    }
    /**
     * @param login Login.
     * @param oldPwd Old password.
     * @param newPwd New password.
     * @param confPwd New password confirmation.
     * @param {string} [otp] One-time password.
     * @returns Promise.
     */
    changePassword(login, oldPwd, newPwd, confPwd, otp = undefined) {
        const url = `${this.baseUrl_}/${RouteSuffix.CHANGE_PASSWORD}`;
        const options = {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            credentials: 'include',
            body: $.param({
                'login': login,
                'oldPassword': oldPwd,
                'otp': otp,
                'newPassword': newPwd,
                'confirmNewPassword': confPwd,
            }),
        };
        return fetch(url, options)
            .then((resp) => resp.json())
            .then((data) => this.checkUser_(data))
            .then((data) => this.setUser_(data, UserState.LOGGED_IN), () => {
            throw new Error('Change password fail.');
        });
    }
    /**
     * @param login Login name.
     * @param pwd Password.
     * @param {string} [otp] One-time password.
     * @returns Promise.
     */
    login(login, pwd, otp = undefined) {
        const url = `${this.baseUrl_}/${RouteSuffix.LOGIN}`;
        const params = {
            'login': login,
            'password': pwd,
            // The `originalUrl` is used to be able to get a link with the private layers (that will open the
            // login panel, with the `loginMessageRequired` message).
            referrer_to: user.getLoginMessage().value == loginMessageRequired ? this.originalUrl : window.location.href,
        };
        if (otp) {
            Object.assign(params, { 'otp': otp });
        }
        const options = {
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            credentials: 'include',
            body: $.param(params),
        };
        return fetch(url, options)
            .then((resp) => resp.json())
            .then((data) => this.checkUser_(data))
            .then((data) => userTransformer(data))
            .then((data) => this.handleLogin_(false, data), () => {
            throw new Error('Login fail.');
        });
    }
    /**
     * Check the user to have a user with all parameters in all cases.
     * @param data Ajax response.
     * @returns Response.
     */
    checkUser_(data) {
        if (!data) {
            return data;
        }
        const emptyUserProperties = user.getEmptyUserProperties();
        data = { ...emptyUserProperties, ...data };
        return data;
    }
    /**
     * @returns Promise.
     */
    logout() {
        const noReload = this.noReloadRole_ ? this.getRolesNames().includes(this.noReloadRole_) : false;
        const url = `${this.baseUrl_}/${RouteSuffix.LOGOUT}`;
        const options = { method: 'GET', credentials: 'include' };
        return fetch(url, options).then(() => {
            this.resetUser(UserState.LOGGED_OUT, noReload);
        });
    }
    /**
     * @param login Login name.
     * @returns Promise.
     */
    resetPassword(login) {
        const url = `${this.baseUrl_}/${RouteSuffix.RESET_PASSWORD}`;
        const options = {
            method: 'POST',
            credentials: 'include',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            body: $.param({ 'login': login }),
        };
        return fetch(url, options).then((resp) => resp.json().then((data) => data));
    }
    /**
     * @returns Username
     */
    getUsername() {
        return this.user_.username || null;
    }
    /**
     * @returns User's email
     */
    getEmail() {
        return this.user_.email || null;
    }
    /**
     * @returns The roles IDs.
     */
    getRolesIds() {
        return this.user_.roles ? this.user_.roles.map((role) => role.id) : [];
    }
    /**
     * @returns The roles names.
     */
    getRolesNames() {
        return this.user_.roles ? this.user_.roles.map((role) => role.name) : [];
    }
    /**
     * @param checkingLoginStatus Checking the login status?
     * @param data Ajax response.
     * @returns Response.
     * @private
     */
    handleLogin_(checkingLoginStatus, data) {
        const userState = checkingLoginStatus ? UserState.READY : UserState.LOGGED_IN;
        this.setUser_(data, userState);
        return data;
    }
    /**
     * @param respData Response.
     * @param userState state of the user.
     * @private
     */
    setUser_(respData, userState) {
        Sentry.setUser({
            username: respData.username,
        });
        user.setUser(respData, userState);
    }
    /**
     * @param userState state of the user.
     * @param noReload Don't request a new user object from
     * the back-end after logging out, defaults to false.
     */
    resetUser(userState, noReload) {
        const emptyUserProperties = user.getEmptyUserProperties();
        user.setUser(emptyUserProperties, userState);
        if (!noReload) {
            this.load_();
        }
    }
}
const ngeoAuthService = new AuthenticationService();
export default ngeoAuthService;
//# sourceMappingURL=service.js.map