import { i as initializeApp } from './index.esm2017-3967344f.js';
import { o as onDisconnect, s as set, r as remove, a as ref, b as onValue, c as child, g as getAuth, d as connectAuthEmulator, e as reload, f as getIdTokenResult, h as getIdToken, i as isSignInWithEmailLink, j as signInWithEmailLink, G as GoogleAuthProvider, k as signInWithCredential, l as signInWithCustomToken, m as signInWithPhoneNumber, n as sendSignInLinkToEmail, p as signInAnonymously, q as onAuthStateChanged, t as createUserWithEmailAndPassword, u as sendEmailVerification, v as sendPasswordResetEmail, w as signInWithEmailAndPassword, x as updateEmail, F as FacebookAuthProvider, T as TwitterAuthProvider, y as signInWithRedirect, z as signInWithPopup, A as signOut, B as reauthenticateWithCredential, C as updatePassword, E as getDatabase } from './index-03e082f4.js';

class SessionService {
    ref;
    metadata;
    onError;
    setMetadataPromise;
    constructor(ref, metadata, onError) {
        this.ref = ref;
        this.metadata = metadata;
        this.onError = onError;
        onDisconnect(this.ref)
            .remove()
            .then(() => {
            // onDisconnect registered!
            this.setMetadataPromise = set(this.ref, metadata);
            this.setMetadataPromise.catch(onError);
        }, onError);
    }
    updateMetadata(newMetadata) {
        this.metadata = newMetadata;
        if (this.setMetadataPromise) {
            this.setMetadataPromise = this.setMetadataPromise.then(() => {
                var promise = set(this.ref, this.metadata);
                promise.catch(this.onError);
                return promise;
            });
        }
    }
    end() {
        if (this.setMetadataPromise) {
            return this.setMetadataPromise.then(() => {
                return remove(this.ref).then(() => {
                    this.setMetadataPromise = null;
                    return this.end();
                }, this.onError);
            }, function () { });
        }
        else {
            return onDisconnect(this.ref).cancel().catch(this.onError);
        }
    }
}

class SessionManager {
    metadata = true;
    session = null;
    user = null;
    forceOffline = true;
    auth = null;
    ref;
    databaseConnected = null;
    constructor(rdb, auth) {
        this.auth = auth;
        this.user = auth?.currentUser;
        this.ref = ref(rdb, "_firebase_extensions/presence");
        onValue(ref(rdb, ".info/connected"), (snapshot) => {
            this.databaseConnected = snapshot.val();
            if (this.session && !this.databaseConnected) {
                this.session.end();
                this.session = null;
            }
            this.createSessionIfNeeded();
        });
        this.auth.onAuthStateChanged((newUser) => {
            if (this.session && (!newUser || newUser.uid !== this.user.uid)) {
                // Don't bother ending the session here since the client is no longer
                // authenticated to RTDB as the original user. Writes would be denied.
                this.session = null;
            }
            this.user = newUser;
            this.createSessionIfNeeded();
        });
    }
    randomId() {
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        var id = "";
        for (var i = 0; i < 20; i++) {
            id += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return id;
    }
    setMetadata(newMetadata) {
        if (newMetadata != null) {
            this.metadata = newMetadata;
        }
        else {
            // RTDB does not allow null/undefined as a value, so:
            this.metadata = true;
        }
        if (this.session) {
            this.session.updateMetadata(this.metadata);
        }
    }
    goOffline() {
        this.forceOffline = true;
        if (this.session) {
            var promise = this.session.end();
            this.session = null;
            return promise;
        }
        else {
            return Promise.resolve();
        }
    }
    goOnline() {
        this.forceOffline = false;
        this.createSessionIfNeeded();
        return Promise.resolve();
    }
    createSessionIfNeeded() {
        if (!this.session &&
            !this.forceOffline &&
            this.databaseConnected &&
            this.user) {
            var sessionId = this.randomId();
            var sessionRef = child(this.ref, `${this.user.uid}/sessions/${sessionId}`);
            this.session = new SessionService(sessionRef, this.metadata, this.onSessionError);
        }
    }
    onSessionError(err) {
        console.warn("Error updating presence", err);
        this.session.end();
        this.session = null;
        if (err.code !== "PERMISSION_DENIED") {
            setTimeout(this.createSessionIfNeeded, 1000);
        }
    }
}

class AuthService {
    app;
    sessionManager;
    config = {
        authLocalStorageKey: "enjin:session",
        tokenLocalStorageKey: "enjin:token",
        facebook: {
            permissions: ["email", "public_profile", "user_friends"],
        },
    };
    isOnline = false;
    service;
    constructor(options) {
        this.config = { ...this.config, ...(options?.config || {}) };
        this.app = options?.app || null;
        const isWindow = typeof window !== "undefined" && window;
        if (!this.app && isWindow) {
            try {
                this.app = initializeApp(options?.config?.firebase);
                console.log("Initializing Firebase App...", this.app);
            }
            catch (e) {
                console.log(e);
            }
        }
        this.service = isWindow ? getAuth(this.app) : null;
        if (!this.config.googlePlus ||
            !this.config.googlePlus.options ||
            !this.config.googlePlus.options.webClientId) {
            console.log("googlePlus.options.webClientId is required for Google Native Auth See Here: https://github.com/EddyVerbruggen/cordova-plugin-googleplus#6-usage");
        }
        if (this.config?.emulate && isWindow) {
            connectAuthEmulator(this.service, "http://localhost:9099");
        }
        if (isWindow)
            this.onEmailLink(window.location.href);
    }
    // async initializePushNotifications(
    //   onMessageCallback?: (payload: any) => void,
    //   options?: { vapidKey?: string }
    // ) {
    //   try {
    //     const messaging = getMessaging(this.app);
    //     if (onMessageCallback && typeof onMessageCallback === "function") {
    //       onMessage(messaging, onMessageCallback);
    //     }
    //     const vapidKey = options?.vapidKey;
    //     let messagingToken = await getToken(messaging, {
    //       vapidKey,
    //       serviceWorkerRegistration:
    //         await navigator.serviceWorker.getRegistration(),
    //     });
    //     if (!messagingToken) {
    //       const permission = await Notification.requestPermission();
    //       if (permission === "granted") {
    //         console.log("Notification permission granted.");
    //         messagingToken = await getToken(messaging, {
    //           vapidKey,
    //           serviceWorkerRegistration:
    //             await navigator.serviceWorker.getRegistration(),
    //         });
    //       } else {
    //         console.log("Unable to get permission to notify.");
    //       }
    //     }
    //     return messagingToken;
    //   } catch (error) {
    //     console.log(
    //       "Service worker not enabled, push notifications will not work!",
    //       error
    //     );
    //   }
    // }
    async getUser(skipReload) {
        if (!skipReload)
            await reload(this.service.currentUser);
        return this.service.currentUser;
    }
    async getClaims() {
        try {
            await reload(this.service.currentUser);
            const { claims } = await getIdTokenResult(this.service?.currentUser);
            return claims;
        }
        catch (error) {
            return {};
        }
    }
    async getToken() {
        const currentToken = this.service?.currentUser
            ? await getIdToken(this.service.currentUser)
            : localStorage.getItem(this.config?.tokenLocalStorageKey || "");
        await this.setToken(currentToken);
        return currentToken;
    }
    async setToken(token) {
        localStorage.setItem(this.config.tokenLocalStorageKey || "", token);
        return token;
    }
    async onEmailLink(link) {
        if (isSignInWithEmailLink(this.service, link)) {
            let email = window.localStorage.getItem("emailForSignIn");
            if (!email) {
                email = window.prompt("Please provide your email for confirmation");
            }
            const authUser = await signInWithEmailLink(this.service, email || "", link);
            window.localStorage.removeItem("emailForSignIn");
            this.emitLoggedInEvent(authUser);
            return authUser;
        }
    }
    // createCaptcha(buttonEl: HTMLButtonElement) {
    //   return new Promise((resolve, reject) => {
    //     try {
    //       (window as any).RecaptchaVerifier = new RecaptchaVerifier(
    //         buttonEl,
    //         {
    //           size: "invisible",
    //           callback(response) {
    //             resolve(response);
    //           },
    //         }
    //       );
    //     } catch (error) {
    //       reject(error);
    //     }
    //   });
    // }
    // createRecapchaWidget(id: string) {
    //   (window as any).recaptchaVerifier = new RecaptchaVerifier(id);
    // }
    withGoogleCredential(token) {
        return GoogleAuthProvider.credential(token);
    }
    withCredential(credential) {
        return signInWithCredential(this.service, credential);
    }
    withToken(token) {
        return signInWithCustomToken(this.service, token);
    }
    withPhoneNumber(phoneNumber, capId) {
        phoneNumber = "+" + phoneNumber;
        window.localStorage.setItem("phoneForSignIn", phoneNumber);
        return signInWithPhoneNumber(this.service, phoneNumber, capId);
    }
    withEmailLink(email, actionCodeSettings) {
        window.localStorage.setItem("emailForSignIn", email);
        return sendSignInLinkToEmail(this.service, email, actionCodeSettings);
    }
    anonymously() {
        return signInAnonymously(this.service);
    }
    onAuthChanged(callback) {
        onAuthStateChanged(this.service, async (session) => {
            if (!session ||
                (!session.emailVerified &&
                    session.providerData &&
                    session.providerData[0].providerId === "password")) {
                return false;
            }
            if (session) {
                localStorage.setItem(this.config?.authLocalStorageKey || "", JSON.stringify(session));
                localStorage.setItem(this.config?.tokenLocalStorageKey || "", await getIdToken(this.service?.currentUser, true));
            }
            if (callback && typeof callback === "function") {
                callback(session);
            }
        });
        if (!localStorage.getItem(this.config?.authLocalStorageKey || "")) {
            callback(null);
        }
    }
    getFromStorage() {
        return localStorage.getItem(this.config?.authLocalStorageKey || "")
            ? JSON.parse(localStorage.getItem(this.config?.authLocalStorageKey || ""))
            : null;
    }
    isLoggedIn() {
        const session = this.service;
        return session ? session : this.getFromStorage();
    }
    emitLoggedInEvent(data) {
        document.body.dispatchEvent(new CustomEvent("authLoggedIn", { detail: { data } }));
    }
    emitLoggedOutEvent() {
        document.body.dispatchEvent(new CustomEvent("authLoggedOut", { detail: {} }));
    }
    createUser(email, password) {
        return createUserWithEmailAndPassword(this.service, email, password);
    }
    sendEmailVerification(options) {
        return sendEmailVerification(this.service.currentUser, options ? options : null);
    }
    sendPasswordReset(emailAddress, options) {
        return sendPasswordResetEmail(this.service, emailAddress, options ? options : null);
    }
    withEmail(email, password) {
        return new Promise((resolve, reject) => {
            try {
                signInWithEmailAndPassword(this.service, email, password)
                    .then((user) => {
                    this.emitLoggedInEvent({ user });
                    resolve({ data: { user } });
                })
                    .catch((error) => {
                    reject(error);
                });
            }
            catch (e) {
                reject(e);
            }
        });
    }
    updateEmail(newEmail, actionOptions) {
        return new Promise((resolve, reject) => {
            try {
                updateEmail(this.service?.currentUser, newEmail)
                    .then((user) => {
                    resolve({ data: { user } });
                    this.sendEmailVerification(actionOptions);
                })
                    .catch((error) => {
                    reject(error);
                });
            }
            catch (e) {
                reject(e);
            }
        });
    }
    async withSocial(network, redirect = false) {
        let provider;
        let shouldRedirect = redirect;
        if (window.matchMedia("(display-mode: standalone)").matches) {
            console.log("Running in PWA mode...");
            shouldRedirect = true;
        }
        return new Promise(async (resolve, reject) => {
            if (network === "facebook") {
                provider = new FacebookAuthProvider();
            }
            else if (network === "google") {
                provider = new GoogleAuthProvider();
            }
            else if (network === "twitter") {
                provider = new TwitterAuthProvider();
            }
            else {
                reject({
                    message: "A social network is required or the one provided is not yet supported.",
                });
            }
            try {
                if (shouldRedirect) {
                    await signInWithRedirect(this.service, provider);
                }
                else {
                    await signInWithPopup(this.service, provider);
                }
                this.emitLoggedInEvent({ currentUser: this.service.currentUser });
            }
            catch (error) {
                console.log(error);
            }
        });
    }
    logout() {
        this.emitLoggedOutEvent();
        return signOut(this.service);
    }
    async updatePassword(newPassword, credential) {
        if (credential) {
            await reauthenticateWithCredential(this.service?.currentUser, credential);
        }
        return updatePassword(this.service.currentUser, newPassword);
    }
    async storeRoles(roles) {
        localStorage.setItem("roles", JSON.stringify(roles));
        return roles;
    }
    async checkRolePermission(roleId, permission, ignoreAdmin) {
        let roles = [];
        const claims = await this.getClaims();
        if (!ignoreAdmin && claims?.admin) {
            return true;
        }
        try {
            roles = JSON.parse(localStorage.getItem("roles"));
        }
        catch (e) {
            console.log("Error getting roles from local storage");
        }
        for (const role of roles) {
            if (role.id === roleId &&
                role.permissions &&
                role.permissions.includes(permission)) {
                return true;
            }
        }
        return false;
    }
    async goOnline() {
        if (!this.sessionManager) {
            const rdb = getDatabase(this.app);
            this.sessionManager = new SessionManager(rdb, this.service);
        }
        this.isOnline = true;
        document.body.dispatchEvent(new CustomEvent("fireenjin:online", {
            detail: { sessionManager: this.sessionManager },
        }));
        return this.sessionManager.goOnline();
    }
    async goOffline() {
        if (!this.sessionManager)
            return null;
        this.isOnline = false;
        document.body.dispatchEvent(new CustomEvent("fireenjin:offline", {
            detail: { sessionManager: this.sessionManager },
        }));
        return this.sessionManager.goOffline();
    }
    async getSessionManager() {
        return this.sessionManager;
    }
    async getApp() {
        return this.app;
    }
    async getService() {
        return this.service;
    }
}

export { AuthService as A };
