import { Injectable, Injector, Optional, Directive, TemplateRef, ViewContainerRef, Input, ɵɵdefineInjectable, ɵɵinject, APP_INITIALIZER, NgModule } from '@angular/core';
import { first, map, tap, distinctUntilChanged, catchError, filter, take, switchMap, finalize } from 'rxjs/operators';
import { __awaiter, __generator, __rest, __spread } from 'tslib';
import { Storage } from '@bravobit/bb-foundation/storage';
import { Api, ApiError } from '@bravobit/bb-foundation/api';
import { BehaviorSubject, of, throwError } from 'rxjs';
import { Router } from '@angular/router';
import { HttpErrorResponse, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/token.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthToken() { }
if (false) {
    /** @type {?|undefined} */
    AuthToken.prototype.id;
    /** @type {?|undefined} */
    AuthToken.prototype.type;
    /** @type {?|undefined} */
    AuthToken.prototype.audience;
    /** @type {?|undefined} */
    AuthToken.prototype.issuer;
    /** @type {?|undefined} */
    AuthToken.prototype.subject;
    /** @type {?|undefined} */
    AuthToken.prototype.notValidBefore;
    /** @type {?|undefined} */
    AuthToken.prototype.expiresAt;
    /** @type {?|undefined} */
    AuthToken.prototype.issuedAt;
    /** @type {?|undefined} */
    AuthToken.prototype.role;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/config.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var AuthConfig = /** @class */ (function () {
    function AuthConfig() {
    }
    return AuthConfig;
}());
if (false) {
    /** @type {?} */
    AuthConfig.prototype.scheme;
    /** @type {?} */
    AuthConfig.prototype.redirectUrl;
    /** @type {?} */
    AuthConfig.prototype.loggedInUrl;
    /** @type {?} */
    AuthConfig.prototype.bootstrap;
    /** @type {?} */
    AuthConfig.prototype.applicationId;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/mapper.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthMapperProtocol() { }
if (false) {
    /** @type {?} */
    AuthMapperProtocol.prototype.me;
    /** @type {?} */
    AuthMapperProtocol.prototype.register;
    /** @type {?} */
    AuthMapperProtocol.prototype.logout;
    /** @type {?} */
    AuthMapperProtocol.prototype.refresh;
    /** @type {?} */
    AuthMapperProtocol.prototype.resetPassword;
    /** @type {?} */
    AuthMapperProtocol.prototype.requestPassword;
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.role = function (data) { };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.toRegister = function (data) { };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapperProtocol.prototype.toRefresh = function (data) { };
}
/**
 * @record
 */
function AuthTokenResponse() { }
if (false) {
    /** @type {?} */
    AuthTokenResponse.prototype.accessToken;
    /** @type {?} */
    AuthTokenResponse.prototype.refreshToken;
}
/**
 * @record
 */
function AuthUserTokenResponse() { }
if (false) {
    /** @type {?} */
    AuthUserTokenResponse.prototype.user;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/interfaces/provider.interface.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/**
 * @record
 */
function AuthProvider() { }
if (false) {
    /**
     * @param {?} api
     * @return {?}
     */
    AuthProvider.prototype.authenticate = function (api) { };
}
/**
 * @record
 */
function AuthProviderResponse() { }
if (false) {
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.user;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.provider;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.verifyToken;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.accessToken;
    /** @type {?|undefined} */
    AuthProviderResponse.prototype.refreshToken;
}
/**
 * @record
 */
function AuthSignInResponse() { }
if (false) {
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.user;
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.provider;
    /** @type {?|undefined} */
    AuthSignInResponse.prototype.verifyToken;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/helpers/jwt.helper.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var JwtHelper = /** @class */ (function () {
    function JwtHelper() {
        var _this = this;
        this.baseDecodeUnicode = (/**
         * @param {?} value
         * @return {?}
         */
        function (value) {
            return decodeURIComponent(atob(value).replace(/(.)/g, (/**
             * @param {?} m
             * @param {?} p
             * @return {?}
             */
            function (m, p) {
                /** @type {?} */
                var code = p.charCodeAt(0).toString(16).toUpperCase();
                if (code.length < 2) {
                    code = '0' + code;
                }
                return '%' + code;
            })));
        });
        this.parse = (/**
         * @param {?} data
         * @return {?}
         */
        function (data) {
            return (/** @type {?} */ ({
                id: data['iss'] || null,
                type: data['typ'] || null,
                audience: data['aud'] || null,
                issuer: data['iss'] || null,
                subject: data['sub'] || null,
                role: data['role'] || null,
                notValidBefore: _this.parseDate(data['nbf']),
                expiresAt: _this.parseDate(data['exp']),
                issuedAt: _this.parseDate(data['iat'])
            }));
        });
        this.parseDate = (/**
         * @param {?} epochInSeconds
         * @return {?}
         */
        function (epochInSeconds) {
            if (!epochInSeconds || epochInSeconds <= 0) {
                return null;
            }
            return new Date(epochInSeconds * 1000);
        });
    }
    /**
     * @param {?} token
     * @return {?}
     */
    JwtHelper.prototype.decode = /**
     * @param {?} token
     * @return {?}
     */
    function (token) {
        try {
            /** @type {?} */
            var json = JSON.parse(this.urlDecode(token.split('.')[1]));
            return this.parse(json);
        }
        catch (_a) {
            return null;
        }
    };
    /**
     * @private
     * @param {?} token
     * @return {?}
     */
    JwtHelper.prototype.urlDecode = /**
     * @private
     * @param {?} token
     * @return {?}
     */
    function (token) {
        /** @type {?} */
        var value = token || '';
        /** @type {?} */
        var output = value
            .replace(/-/g, '+')
            .replace(/_/g, '/');
        switch (output.length % 4) {
            case 0:
                break;
            case 2:
                output += '==';
                break;
            case 3:
                output += '=';
                break;
            default:
                throw 'Illegal base64url string!';
        }
        try {
            return this.baseDecodeUnicode(output);
        }
        catch (_a) {
            return atob(output);
        }
    };
    return JwtHelper;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.baseDecodeUnicode;
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.parse;
    /**
     * @type {?}
     * @private
     */
    JwtHelper.prototype.parseDate;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/helpers/mapper.helper.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var AuthMapper = /** @class */ (function () {
    function AuthMapper() {
        // Routes.
        this.me = 'auth/me';
        this.register = 'auth/register';
        this.logout = 'auth/logout';
        this.refresh = 'auth/refresh';
        this.requestPassword = 'auth/reset';
        this.resetPassword = 'auth/reset-password';
    }
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapper.prototype.role = /**
     * @param {?} data
     * @return {?}
     */
    function (data) {
        return (data && data.role) || null;
    };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapper.prototype.toRegister = /**
     * @param {?} data
     * @return {?}
     */
    function (data) {
        // Retrieve the params.
        var token = data.token, refresh_token = data.refresh_token, user = data.user;
        // Map the data to the correct format.
        return { accessToken: token, refreshToken: refresh_token, user: user };
    };
    /**
     * @param {?} data
     * @return {?}
     */
    AuthMapper.prototype.toRefresh = /**
     * @param {?} data
     * @return {?}
     */
    function (data) {
        // Retrieve the params.
        var token = data.token, refresh_token = data.refresh_token;
        // Map the data to the correct format.
        return { accessToken: token, refreshToken: refresh_token };
    };
    return AuthMapper;
}());
if (false) {
    /** @type {?} */
    AuthMapper.prototype.me;
    /** @type {?} */
    AuthMapper.prototype.register;
    /** @type {?} */
    AuthMapper.prototype.logout;
    /** @type {?} */
    AuthMapper.prototype.refresh;
    /** @type {?} */
    AuthMapper.prototype.requestPassword;
    /** @type {?} */
    AuthMapper.prototype.resetPassword;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/providers/verify.provider.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var AuthVerifyProvider = /** @class */ (function () {
    function AuthVerifyProvider(_code, _verifyToken, _endpoint) {
        if (_endpoint === void 0) { _endpoint = 'auth/verify'; }
        this._code = _code;
        this._verifyToken = _verifyToken;
        this._endpoint = _endpoint;
    }
    /**
     * @param {?} api
     * @return {?}
     */
    AuthVerifyProvider.prototype.authenticate = /**
     * @param {?} api
     * @return {?}
     */
    function (api) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, token, refresh_token, user;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        // Execute API call.
                        return [4 /*yield*/, api.post(this._endpoint, {
                                token: this._code,
                                verify_token: this._verifyToken
                            })];
                    case 1:
                        _a = _b.sent(), token = _a.token, refresh_token = _a.refresh_token, user = _a.user;
                        // Map the data to the correct format.
                        return [2 /*return*/, { accessToken: token, refreshToken: refresh_token, user: user }];
                }
            });
        });
    };
    return AuthVerifyProvider;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._code;
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._verifyToken;
    /**
     * @type {?}
     * @private
     */
    AuthVerifyProvider.prototype._endpoint;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/providers/email.provider.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var AuthEmailProvider = /** @class */ (function () {
    function AuthEmailProvider(_email, _password, _endpoint) {
        if (_endpoint === void 0) { _endpoint = 'auth/login'; }
        this._email = _email;
        this._password = _password;
        this._endpoint = _endpoint;
    }
    /**
     * @param {?} api
     * @return {?}
     */
    AuthEmailProvider.prototype.authenticate = /**
     * @param {?} api
     * @return {?}
     */
    function (api) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, token, refresh_token, user, provider, verify_token;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        // Execute API call.
                        return [4 /*yield*/, api.post(this._endpoint, {
                                email: this._email,
                                password: this._password
                            })];
                    case 1:
                        _a = _b.sent(), token = _a.token, refresh_token = _a.refresh_token, user = _a.user, provider = _a.provider, verify_token = _a.verify_token;
                        // Map the data to the correct format.
                        return [2 /*return*/, {
                                accessToken: token,
                                refreshToken: refresh_token,
                                user: user,
                                provider: provider,
                                verifyToken: verify_token
                            }];
                }
            });
        });
    };
    return AuthEmailProvider;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._email;
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._password;
    /**
     * @type {?}
     * @private
     */
    AuthEmailProvider.prototype._endpoint;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.service.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var Auth = /** @class */ (function () {
    function Auth(_storage, _mapper, _injector, _api, _config) {
        this._storage = _storage;
        this._mapper = _mapper;
        this._injector = _injector;
        this._api = _api;
        this._config = _config;
        // Data.
        this._user$ = new BehaviorSubject(null);
        // Validate the API was injected.
        if (!this._api) {
            throw new Error('The API is required for this module to work.');
        }
        // Set the storage keys based on the application id.
        /** @type {?} */
        var applicationId = (this._config && this._config.applicationId) || 'angular';
        this._apiUserStorageKey = applicationId + "_auth-user";
        this._apiTokenStorageKey = applicationId + "_auth-token";
        this._apiRefreshTokenStorageKey = applicationId + "_auth-refresh-token";
        // Fetch the user from the storage.
        /** @type {?} */
        var user = this._storage.cookie.get(this._apiUserStorageKey);
        // Cache the user in memory.
        this._user$.next(user);
    }
    Object.defineProperty(Auth.prototype, "router", {
        get: /**
         * @private
         * @return {?}
         */
        function () {
            return this._injector.get(Router);
        },
        enumerable: true,
        configurable: true
    });
    /**
     * @return {?}
     */
    Auth.prototype.initialize = /**
     * @return {?}
     */
    function () {
        var _this = this;
        return (/**
         * @return {?}
         */
        function () { return __awaiter(_this, void 0, void 0, function () {
            var shouldBootstrap, user;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        shouldBootstrap = (this._config && this._config.bootstrap) === undefined
                            ? true
                            : this._config.bootstrap;
                        // Check if the app should bootstrap
                        // the authentication.
                        if (!shouldBootstrap) {
                            return [2 /*return*/];
                        }
                        // Only retrieve from the server
                        // when an access token is saved.
                        if (!this.accessToken && !this.refreshToken) {
                            return [2 /*return*/];
                        }
                        // Try to fetch the user from the server.
                        return [4 /*yield*/, this.me().pipe(first()).toPromise()];
                    case 1:
                        user = _a.sent();
                        // Save the user in the storage.
                        return [2 /*return*/, this.setUser(user)];
                }
            });
        }); });
    };
    Object.defineProperty(Auth.prototype, "isAuthenticated", {
        get: /**
         * @return {?}
         */
        function () {
            return !!this.payload;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Auth.prototype, "user", {
        get: /**
         * @return {?}
         */
        function () {
            return this._user$.asObservable();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Auth.prototype, "accessToken", {
        get: /**
         * @return {?}
         */
        function () {
            return this._storage.cookie.get(this._apiTokenStorageKey);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Auth.prototype, "refreshToken", {
        get: /**
         * @return {?}
         */
        function () {
            return this._storage.cookie.get(this._apiRefreshTokenStorageKey);
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Auth.prototype, "payload", {
        get: /**
         * @return {?}
         */
        function () {
            return new JwtHelper().decode(this.accessToken);
        },
        enumerable: true,
        configurable: true
    });
    /**
     * @template T
     * @return {?}
     */
    Auth.prototype.me = /**
     * @template T
     * @return {?}
     */
    function () {
        return this._api.get(this._mapper.me);
    };
    /**
     * @param {?} provider
     * @param {?=} as
     * @return {?}
     */
    Auth.prototype.signIn = /**
     * @param {?} provider
     * @param {?=} as
     * @return {?}
     */
    function (provider, as) {
        return __awaiter(this, void 0, void 0, function () {
            var _a, accessToken, refreshToken, user, result, apiProvider, apiVerifyToken, availableProviders;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0: return [4 /*yield*/, provider.authenticate(this._api)];
                    case 1:
                        _a = _b.sent(), accessToken = _a.accessToken, refreshToken = _a.refreshToken, user = _a.user, result = __rest(_a, ["accessToken", "refreshToken", "user"]);
                        // Check if the role matches.
                        if (as && !as.includes(this._mapper.role(user))) {
                            throw new Error('Invalid role.');
                        }
                        // Validate if the provider is one of the available
                        // providers then return the user object and the provider.
                        apiProvider = (result && result.provider) || null;
                        apiVerifyToken = (result && result.verifyToken) || null;
                        availableProviders = ['email'];
                        if (availableProviders.includes(apiProvider)) {
                            return [2 /*return*/, (/** @type {?} */ ({ user: user, provider: apiProvider, verifyToken: apiVerifyToken }))];
                        }
                        // Set the tokens in storage.
                        this.setTokens(accessToken, refreshToken);
                        // Set the user in storage.
                        this.setUser(user);
                        // Return the user.
                        return [2 /*return*/, (/** @type {?} */ ({ user: user }))];
                }
            });
        });
    };
    /**
     * @param {?} email
     * @param {?} password
     * @param {?=} as
     * @return {?}
     */
    Auth.prototype.signInWithEmail = /**
     * @param {?} email
     * @param {?} password
     * @param {?=} as
     * @return {?}
     */
    function (email, password, as) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, this.signIn(new AuthEmailProvider(email, password), as)];
            });
        });
    };
    /**
     * @param {?} code
     * @param {?} verifyToken
     * @return {?}
     */
    Auth.prototype.signInWithVerifyCode = /**
     * @param {?} code
     * @param {?} verifyToken
     * @return {?}
     */
    function (code, verifyToken) {
        return __awaiter(this, void 0, void 0, function () {
            return __generator(this, function (_a) {
                return [2 /*return*/, this.signIn(new AuthVerifyProvider(code, verifyToken))];
            });
        });
    };
    /**
     * @template T
     * @param {?} data
     * @return {?}
     */
    Auth.prototype.register = /**
     * @template T
     * @param {?} data
     * @return {?}
     */
    function (data) {
        return __awaiter(this, void 0, void 0, function () {
            var result, _a, accessToken, refreshToken, user;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        // Execute API call.
                        return [4 /*yield*/, this._api.post(this._mapper.register, data)];
                    case 1:
                        result = _b.sent();
                        // Map to the correct response.
                        _a = this._mapper.toRegister(result), accessToken = _a.accessToken, refreshToken = _a.refreshToken, user = _a.user;
                        // Set the tokens in storage.
                        this.setTokens(accessToken, refreshToken);
                        // Set the user in storage.
                        this.setUser(user);
                        // Return the user.
                        return [2 /*return*/, user];
                }
            });
        });
    };
    /**
     * @return {?}
     */
    Auth.prototype.logout = /**
     * @return {?}
     */
    function () {
        try {
            // Log the user out.
            this._api.get(this._mapper.logout, { headers: { Authorization: this.refreshToken } })
                .toPromise().then((/**
             * @param {?} _
             * @return {?}
             */
            function (_) { return _; }));
        }
        catch (_a) {
            // Do nothing because the tokens will be deleted anyways from the storage.
        }
        // Delete the tokens from the session.
        return this.clear();
    };
    /**
     * @return {?}
     */
    Auth.prototype.refresh = /**
     * @return {?}
     */
    function () {
        var _this = this;
        // If the refresh token does
        // not exist just return an observable of null.
        if (!this.refreshToken) {
            return of(null);
        }
        // Perform the refresh call.
        /** @type {?} */
        var scheme = (this._config && this._config.scheme) || 'Bearer';
        return this._api.get(this._mapper.refresh, {
            headers: {
                'Authorization': scheme + " " + this.refreshToken,
                'X-No-Authorization': 'yes'
            }
        }).pipe(map((/**
         * @param {?} data
         * @return {?}
         */
        function (data) { return _this._mapper.toRefresh(data); })), tap((/**
         * @param {?} __0
         * @return {?}
         */
        function (_a) {
            var accessToken = _a.accessToken, refreshToken = _a.refreshToken;
            return _this.setTokens(accessToken, refreshToken);
        })), map((/**
         * @param {?} __0
         * @return {?}
         */
        function (_a) {
            var accessToken = _a.accessToken;
            return accessToken;
        })));
    };
    /**
     * @param {?} email
     * @return {?}
     */
    Auth.prototype.requestPassword = /**
     * @param {?} email
     * @return {?}
     */
    function (email) {
        return __awaiter(this, void 0, void 0, function () {
            var error_1;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this._api.post(this._mapper.requestPassword, { email: email })];
                    case 1: return [2 /*return*/, _a.sent()];
                    case 2:
                        error_1 = _a.sent();
                        throw error_1;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * @param {?} token
     * @param {?} newPassword
     * @return {?}
     */
    Auth.prototype.resetPassword = /**
     * @param {?} token
     * @param {?} newPassword
     * @return {?}
     */
    function (token, newPassword) {
        return __awaiter(this, void 0, void 0, function () {
            var error_2;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this._api.post(this._mapper.resetPassword, { token: token, password: newPassword })];
                    case 1: return [2 /*return*/, _a.sent()];
                    case 2:
                        error_2 = _a.sent();
                        throw error_2;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * @param {?} type
     * @return {?}
     */
    Auth.prototype.guard = /**
     * @param {?} type
     * @return {?}
     */
    function (type) {
        /** @type {?} */
        var url = null;
        switch (type) {
            case 'authenticated':
                url = this._config && this._config.loggedInUrl;
                break;
            case 'unauthenticated':
                url = this._config && this._config.redirectUrl;
                break;
        }
        if (this.router && url) {
            return this.router.parseUrl(url);
        }
        return false;
    };
    /**
     * @param {?=} accessToken
     * @param {?=} refreshToken
     * @return {?}
     */
    Auth.prototype.setTokens = /**
     * @param {?=} accessToken
     * @param {?=} refreshToken
     * @return {?}
     */
    function (accessToken, refreshToken) {
        // Set the token if the token exists.
        if (accessToken) {
            var expiresAt = new JwtHelper().decode(accessToken).expiresAt;
            this._storage.cookie.set(this._apiTokenStorageKey, accessToken, {
                expires: expiresAt
            });
        }
        // Set the refresh token if the refresh token exists.
        if (refreshToken) {
            var expiresAt = new JwtHelper().decode(refreshToken).expiresAt;
            this._storage.cookie.set(this._apiRefreshTokenStorageKey, refreshToken, {
                expires: expiresAt
            });
        }
    };
    /**
     * @param {?} user
     * @return {?}
     */
    Auth.prototype.setUser = /**
     * @param {?} user
     * @return {?}
     */
    function (user) {
        // Validate the user exists.
        if (!user) {
            return;
        }
        // Push the next user.
        this._user$.next(user);
        // Make the user data valid for one year.
        /** @type {?} */
        var date = new Date();
        date.setFullYear(date.getFullYear() + 1);
        /** @type {?} */
        var timestamp = date.getTime();
        // Save the user in the storage.
        return this._storage.cookie.set(this._apiUserStorageKey, user, {
            expires: timestamp
        });
    };
    /**
     * @return {?}
     */
    Auth.prototype.clear = /**
     * @return {?}
     */
    function () {
        // Delete the items from the local storage.
        this._storage.cookie.remove(this._apiUserStorageKey);
        this._storage.cookie.remove(this._apiTokenStorageKey);
        this._storage.cookie.remove(this._apiRefreshTokenStorageKey);
        // Push an empty user.
        this._user$.next(null);
    };
    Auth.decorators = [
        { type: Injectable }
    ];
    /** @nocollapse */
    Auth.ctorParameters = function () { return [
        { type: Storage },
        { type: AuthMapper },
        { type: Injector },
        { type: Api, decorators: [{ type: Optional }] },
        { type: AuthConfig, decorators: [{ type: Optional }] }
    ]; };
    return Auth;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiUserStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiTokenStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._apiRefreshTokenStorageKey;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._user$;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._storage;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._mapper;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._injector;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._api;
    /**
     * @type {?}
     * @private
     */
    Auth.prototype._config;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/directives/authenticated.directive.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var BbAuthenticated = /** @class */ (function () {
    function BbAuthenticated(_auth, _template, _viewContainerRef) {
        this._auth = _auth;
        this._template = _template;
        this._viewContainerRef = _viewContainerRef;
    }
    /**
     * @return {?}
     */
    BbAuthenticated.prototype.ngOnInit = /**
     * @return {?}
     */
    function () {
        var _this = this;
        this._subscription = this._auth.user.pipe(map((/**
         * @param {?} user
         * @return {?}
         */
        function (user) { return !!user; })), distinctUntilChanged()).subscribe((/**
         * @param {?} isAuthenticated
         * @return {?}
         */
        function (isAuthenticated) {
            if (isAuthenticated) {
                _this._viewContainerRef.createEmbeddedView(_this._template);
            }
            else {
                _this._viewContainerRef.clear();
            }
        }));
    };
    /**
     * @return {?}
     */
    BbAuthenticated.prototype.ngOnDestroy = /**
     * @return {?}
     */
    function () {
        this._subscription && this._subscription.unsubscribe();
    };
    BbAuthenticated.decorators = [
        { type: Directive, args: [{
                    selector: '[bbAuthenticated]'
                },] }
    ];
    /** @nocollapse */
    BbAuthenticated.ctorParameters = function () { return [
        { type: Auth },
        { type: TemplateRef },
        { type: ViewContainerRef }
    ]; };
    return BbAuthenticated;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._subscription;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._template;
    /**
     * @type {?}
     * @private
     */
    BbAuthenticated.prototype._viewContainerRef;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/directives/role.directive.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var BbRole = /** @class */ (function () {
    function BbRole(_auth, _template, _viewContainerRef) {
        this._auth = _auth;
        this._template = _template;
        this._viewContainerRef = _viewContainerRef;
        this.getPermissions = (/**
         * @param {?} value
         * @return {?}
         */
        function (value) {
            return Array.isArray(value) ? value : [value];
        });
    }
    /**
     * @return {?}
     */
    BbRole.prototype.ngOnInit = /**
     * @return {?}
     */
    function () {
        var _this = this;
        this._subscription = this._auth.user.pipe(map((/**
         * @param {?} user
         * @return {?}
         */
        function (user) { return (user && user.role) || null; })), distinctUntilChanged()).subscribe((/**
         * @param {?} role
         * @return {?}
         */
        function (role) {
            /** @type {?} */
            var permissions = _this.getPermissions(_this.bbRole);
            if (permissions.includes(role)) {
                _this._viewContainerRef.createEmbeddedView(_this._template);
            }
            else {
                _this._viewContainerRef.clear();
            }
        }));
    };
    /**
     * @return {?}
     */
    BbRole.prototype.ngOnDestroy = /**
     * @return {?}
     */
    function () {
        this._subscription && this._subscription.unsubscribe();
    };
    BbRole.decorators = [
        { type: Directive, args: [{
                    selector: '[bbRole]'
                },] }
    ];
    /** @nocollapse */
    BbRole.ctorParameters = function () { return [
        { type: Auth },
        { type: TemplateRef },
        { type: ViewContainerRef }
    ]; };
    BbRole.propDecorators = {
        bbRole: [{ type: Input }]
    };
    return BbRole;
}());
if (false) {
    /** @type {?} */
    BbRole.prototype.bbRole;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._subscription;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype.getPermissions;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._template;
    /**
     * @type {?}
     * @private
     */
    BbRole.prototype._viewContainerRef;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/guards/anonymous.guard.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var BbAnonymousGuard = /** @class */ (function () {
    function BbAnonymousGuard(_auth) {
        this._auth = _auth;
    }
    /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    BbAnonymousGuard.prototype.canActivate = /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    function (route, state) {
        // If the user is not authenticated it can
        // access the anonymous page.
        if (!this._auth.isAuthenticated) {
            return true;
        }
        // Return the user back to the authenticated page.
        return this._auth.guard('authenticated');
    };
    /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    BbAnonymousGuard.prototype.canActivateChild = /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    function (childRoute, state) {
        return this.canActivate(childRoute, state);
    };
    BbAnonymousGuard.decorators = [
        { type: Injectable, args: [{
                    providedIn: 'root'
                },] }
    ];
    /** @nocollapse */
    BbAnonymousGuard.ctorParameters = function () { return [
        { type: Auth }
    ]; };
    /** @nocollapse */ BbAnonymousGuard.ngInjectableDef = ɵɵdefineInjectable({ factory: function BbAnonymousGuard_Factory() { return new BbAnonymousGuard(ɵɵinject(Auth)); }, token: BbAnonymousGuard, providedIn: "root" });
    return BbAnonymousGuard;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAnonymousGuard.prototype._auth;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/guards/authenticated.guard.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var BbAuthenticatedGuard = /** @class */ (function () {
    function BbAuthenticatedGuard(_auth) {
        this._auth = _auth;
    }
    /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    BbAuthenticatedGuard.prototype.canActivate = /**
     * @param {?} route
     * @param {?} state
     * @return {?}
     */
    function (route, state) {
        // If the user is authenticated it can
        // access the authenticated page.
        if (this._auth.isAuthenticated) {
            return true;
        }
        // The user is not authorized to see that
        // page so un-authorize him.
        return this._auth.guard('unauthenticated');
    };
    /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    BbAuthenticatedGuard.prototype.canActivateChild = /**
     * @param {?} childRoute
     * @param {?} state
     * @return {?}
     */
    function (childRoute, state) {
        return this.canActivate(childRoute, state);
    };
    BbAuthenticatedGuard.decorators = [
        { type: Injectable, args: [{
                    providedIn: 'root'
                },] }
    ];
    /** @nocollapse */
    BbAuthenticatedGuard.ctorParameters = function () { return [
        { type: Auth }
    ]; };
    /** @nocollapse */ BbAuthenticatedGuard.ngInjectableDef = ɵɵdefineInjectable({ factory: function BbAuthenticatedGuard_Factory() { return new BbAuthenticatedGuard(ɵɵinject(Auth)); }, token: BbAuthenticatedGuard, providedIn: "root" });
    return BbAuthenticatedGuard;
}());
if (false) {
    /**
     * @type {?}
     * @private
     */
    BbAuthenticatedGuard.prototype._auth;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.interceptor.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
var AuthInterceptor = /** @class */ (function () {
    function AuthInterceptor(_auth, _router, _config) {
        var _this = this;
        this._auth = _auth;
        this._router = _router;
        this._config = _config;
        // Data.
        this.isRefreshing = false;
        this.token$ = new BehaviorSubject(null);
        this.getToken = (/**
         * @param {?} request
         * @return {?}
         */
        function (request) {
            // Get the token based on header.
            if (request.headers.has('Authorization')) {
                return request.headers.get('Authorization');
            }
            // Return the default access token.
            return _this._auth.accessToken;
        });
        this.composeRequest = (/**
         * @param {?} request
         * @param {?=} token
         * @return {?}
         */
        function (request, token) {
            if (token === void 0) { token = null; }
            // If the token is not set, delete the authorization header.
            if (!token) {
                return request.clone({ headers: request.headers.delete('Authorization') });
            }
            // Get the auth scheme from the config,
            // if the scheme was not set use bearer.
            /** @type {?} */
            var authScheme = (_this._config && _this._config.scheme) || 'Bearer';
            // Clone and add the authorization header.
            return request.clone({
                setHeaders: { Authorization: authScheme + " " + token }
            });
        });
    }
    /**
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    AuthInterceptor.prototype.intercept = /**
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    function (request, next) {
        var _this = this;
        // Just return when the user is performing an refresh request.
        if (request.headers.has('X-No-Authorization')) {
            /** @type {?} */
            var newRequest_1 = request.clone({ headers: request.headers.delete('X-No-Authorization') });
            return next.handle(newRequest_1);
        }
        // Compose the new request.
        /** @type {?} */
        var newRequest = this.composeRequest(request, this.getToken(request));
        // Handle all errors.
        return next.handle(newRequest).pipe(catchError((/**
         * @param {?} error
         * @return {?}
         */
        function (error) {
            // Create a custom error.
            /** @type {?} */
            var apiError = new ApiError(error.status, error.error);
            // Check if it is an error response.
            if (!(error instanceof HttpErrorResponse)) {
                return throwError(apiError);
            }
            // Handle a 401 error.
            if (error.status === 401) {
                return _this.handle401Error(request, next);
            }
            // Just re-throw the error.
            return throwError(apiError);
        })));
    };
    /**
     * @private
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    AuthInterceptor.prototype.handle401Error = /**
     * @private
     * @param {?} request
     * @param {?} next
     * @return {?}
     */
    function (request, next) {
        var _this = this;
        // If already refreshing wait for the token to complete.
        if (this.isRefreshing) {
            return this.token$.pipe(filter((/**
             * @param {?} token
             * @return {?}
             */
            function (token) { return token !== null; })), take(1), switchMap((/**
             * @param {?} token
             * @return {?}
             */
            function (token) { return next.handle(_this.composeRequest(request, token)); })));
        }
        // Set the refreshing to true.
        this.isRefreshing = true;
        this.token$.next(null);
        return this._auth.refresh().pipe(switchMap((/**
         * @param {?} newToken
         * @return {?}
         */
        function (newToken) {
            if (!newToken) {
                return _this.logoutUser();
            }
            _this.token$.next(newToken);
            return next.handle(_this.composeRequest(request, newToken));
        })), catchError((/**
         * @param {?} error
         * @return {?}
         */
        function (error) {
            return _this.logoutUser(error);
        })), finalize((/**
         * @return {?}
         */
        function () {
            _this.isRefreshing = false;
        })));
    };
    /**
     * @private
     * @param {?=} error
     * @return {?}
     */
    AuthInterceptor.prototype.logoutUser = /**
     * @private
     * @param {?=} error
     * @return {?}
     */
    function (error) {
        // Delete the tokens from the session.
        this._auth.clear();
        // Compose the route url.
        /** @type {?} */
        var routeUrl = this._config && this._config.redirectUrl;
        // Route back if the user provided a redirect url.
        if (this._router && routeUrl) {
            this._router.navigate([routeUrl]).then((/**
             * @param {?} _
             * @return {?}
             */
            function (_) { return _; }));
        }
        // Throw the error.
        return throwError(error || 'Invalid refresh token; user was logged out.');
    };
    AuthInterceptor.decorators = [
        { type: Injectable }
    ];
    /** @nocollapse */
    AuthInterceptor.ctorParameters = function () { return [
        { type: Auth },
        { type: Router, decorators: [{ type: Optional }] },
        { type: AuthConfig, decorators: [{ type: Optional }] }
    ]; };
    return AuthInterceptor;
}());
if (false) {
    /** @type {?} */
    AuthInterceptor.prototype.isRefreshing;
    /** @type {?} */
    AuthInterceptor.prototype.token$;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype.getToken;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype.composeRequest;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._auth;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._router;
    /**
     * @type {?}
     * @private
     */
    AuthInterceptor.prototype._config;
}

/**
 * @fileoverview added by tsickle
 * Generated from: lib/auth.module.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
/** @type {?} */
var DECLARATIONS_EXPORTS = [
    BbAuthenticated,
    BbRole
];
var AuthModule = /** @class */ (function () {
    function AuthModule() {
    }
    /**
     * @param {?=} config
     * @return {?}
     */
    AuthModule.forRoot = /**
     * @param {?=} config
     * @return {?}
     */
    function (config) {
        return {
            ngModule: AuthModule,
            providers: [
                Auth,
                { provide: AuthConfig, useValue: config },
                { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
                { useFactory: initializeAuth, provide: APP_INITIALIZER, deps: [Auth], multi: true }
            ]
        };
    };
    AuthModule.decorators = [
        { type: NgModule, args: [{
                    imports: [HttpClientModule],
                    declarations: __spread(DECLARATIONS_EXPORTS),
                    exports: __spread(DECLARATIONS_EXPORTS),
                    providers: [
                        { provide: AuthMapper, useClass: AuthMapper }
                    ]
                },] }
    ];
    return AuthModule;
}());
/**
 * @param {?} auth
 * @return {?}
 */
function initializeAuth(auth) {
    return auth.initialize();
}

/**
 * @fileoverview added by tsickle
 * Generated from: public_api.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

/**
 * @fileoverview added by tsickle
 * Generated from: bravobit-bb-foundation-auth.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */

export { Auth, AuthConfig, AuthEmailProvider, AuthMapper, AuthModule, AuthVerifyProvider, BbAnonymousGuard, BbAuthenticated, BbAuthenticatedGuard, BbRole, JwtHelper, initializeAuth, AuthInterceptor as ɵa };
//# sourceMappingURL=bravobit-bb-foundation-auth.js.map
