import {
  getAuth,
  createUserWithEmailAndPassword,
  signOut,
  onAuthStateChanged,
  signInWithEmailAndPassword,
  updateProfile,
  sendPasswordResetEmail
} from 'firebase/auth';
import { getDatabase, ref, onValue } from 'firebase/database';
import { makeAutoObservable } from 'mobx';
import { currentLocale } from '../app/i18n/Locale';
import {
  UserProfile,
  GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH,
  GET_FIREBASE_STORAGE_RESIZED_IMAGE_PROFILE_PATH
} from './UserProfile';
import {
  getStorage,
  ref as storageRef,
  getDownloadURL,
  deleteObject
} from 'firebase/storage';

export interface UserType {
  displayName: string;
  language: string;
  email?: string;
  photoURL?: string;
  uid?: string;
}

export class User {
  authenticated: boolean;
  authorized: boolean;
  displayName: string;
  language: string;
  email?: string;
  errorCode?: string;
  errorMessage?: string;
  firebaseUser: any;
  photoURL?: string;
  uid?: string;
  firebase: any;
  allowDiscovery: boolean;
  analytics: any;
  connected: boolean;
  lastUpdated?: number;
  profile: UserProfile;
  profilePhotoToken?: string;
  onLogout: () => void;

  constructor(onLogout: () => void) {
    this.authenticated = false; // NOTE: You can be authenticated but not authorized
    this.authorized = false;
    this.language = currentLocale.locale;
    this.allowDiscovery = false;
    this.displayName = '';
    this.connected = false;
    this.lastUpdated = undefined;
    this.email = undefined;
    this.profile = new UserProfile({});
    this.onLogout = onLogout;
    this.profilePhotoToken = undefined;

    makeAutoObservable(this);
  }

  get hasAccess(): boolean {
    return this.authenticated && this.authorized;
  }

  get isPremiumMember(): boolean {
    return this.profile.membership === 'premium';
  }

  initFirebase = () => {
    // Attach observer
    const auth = getAuth();
    onAuthStateChanged(auth, async (user) => {
      if (user) {
        // User is signed in, see docs for a list of available properties
        // https://firebase.google.com/docs/reference/js/firebase.User
        const uid = auth.currentUser?.uid;
        this.setAuthorized(true);
        this.setFirebaseUser(user);
        this.setDisplayName(user?.displayName || undefined);
        this.setPhotoURL(user?.photoURL || undefined);
        this.setUid(uid);
        this.setEmail(user?.email || undefined);
        this.setAuthenticated(true);
        this.detectConnectionState();
      } else {
        // User is signed out
        this.setAuthorized(false);
        this.setAuthenticated(true);
      }
    });
  };

  setFirebase = (firebase: any) => {
    this.firebase = firebase;
  };

  setFirebaseUser = (user: any) => {
    this.firebaseUser = user;
  };

  private setAuthorized = (value: boolean) => {
    this.authorized = value;
  };

  setLanguage = (value: string) => {
    this.language = value;
    currentLocale.setStringsForLocale(value);
  };

  setEmail = (value?: string) => {
    this.email = value;
  };

  setDisplayName = (value?: string) => {
    this.displayName = value || '';
  };

  setUid = (value?: string) => {
    this.uid = value;
  };

  setErrorCode = (value?: string) => {
    this.errorCode = value;
  };

  setErrorMessage = (value?: string) => {
    this.errorMessage = value;
  };

  private setAuthenticated = (value: boolean) => {
    this.authenticated = value;
  };

  setPhotoURL = (value?: string) => {
    this.photoURL = value;
  };

  static getProfileImageUrl = async (userId: string) => {
    const storage = getStorage();
    const imageRefUrl = GET_FIREBASE_STORAGE_RESIZED_IMAGE_PROFILE_PATH(userId);
    const sRef = storageRef(storage, imageRefUrl);
    return await getDownloadURL(sRef);
  };

  setAllowDiscovery = (value?: boolean) => {
    this.allowDiscovery = value || false;
  };

  sendPasswordResetEmail = (email: string) => {
    const auth = getAuth();
    return sendPasswordResetEmail(auth, email);
  };

  signupWithEmailAndPassword = async (email: string, password: string) => {
    this.setAuthenticated(false);
    // using firebase v8
    const auth = getAuth();
    await createUserWithEmailAndPassword(auth, email.toLowerCase(), password)
      .then((userCredential) => {
        // Signed in
        const user = userCredential.user;
        this.setUid(user.uid);
        this.setEmail(user?.email || undefined);
        this.setAuthenticated(true);
        this.setAuthorized(true);

        // CREATE USER PROFILE WHEN SIGNING UP
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;

        this.setAuthenticated(true);
        this.setAuthorized(false);
        this.setErrorMessage(errorMessage);
        this.setErrorCode(errorCode);
      });
  };

  signIn = async (email: string, password: string): Promise<boolean> => {
    console.log('signIn', email, password);
    this.setAuthenticated(false);

    const {
      setUid,
      setEmail,
      setAuthenticated,
      setAuthorized,
      setErrorMessage,
      setErrorCode
    } = this;
    // using firebase v8
    const auth = getAuth();

    const signedIn = await signInWithEmailAndPassword(
      auth,
      email.toLocaleLowerCase(),
      password
    )
      .then((userCredential) => {
        // Signed in
        const user = userCredential.user;
        setUid(user.uid);
        setEmail(user?.email || undefined);
        setAuthenticated(true);
        setAuthorized(true);
        setErrorMessage(undefined);
        setErrorCode(undefined);
        return true;
      })
      .catch((error) => {
        console.log('error', error);
        const errorCode = error.code;
        const errorMessage = error.message;
        setAuthenticated(true);
        setAuthorized(false);
        setErrorMessage(errorMessage);
        setErrorCode(errorCode);
        return false;
      });
    return signedIn;
  };

  updateDisplayName = (displayName: string) => {
    if (this.firebaseUser) {
      // Updates the user attributes:
      updateProfile(this.firebaseUser, {
        displayName
      }).then(
        () => {
          // Profile updated successfully!
          const displayName = this.firebaseUser.displayName;
          this.setDisplayName(displayName);
        },
        (error: any) => {
          // An error happened.
          console.log({ error });
        }
      );
    }
  };

  updatePhotoUrl = (photoURL: string) => {
    if (this.firebaseUser) {
      // Updates the user attributes:
      this.firebaseUser
        .updateProfile({
          photoURL
        })
        .then(
          () => {
            // Profile updated successfully!
            const photoURL = this.firebaseUser.photoURL;
            this.setPhotoURL(photoURL);
          },
          (error: any) => {
            // An error happened.
            console.log({ error });
          }
        );
    }
  };

  logout = () => {
    this.onLogout();
    const auth = getAuth();
    signOut(auth)
      .then(() => {
        // Sign-out successful.
        this.setUid(undefined);
        this.setAuthorized(false);
        this.setAuthenticated(true);
        this.setEmail(undefined);
        this.setDisplayName(undefined);
        this.setPhotoURL(undefined);
      })
      .catch((error) => {
        console.log({ error });
        // An error happened.
      });
  };

  detectConnectionState() {
    const db = getDatabase();
    const connectedRef = ref(db, '.info/connected');
    onValue(connectedRef, (snap) => {
      if (snap.val() === true) {
        this.setConnected(true);
      } else {
        this.setConnected(false);
      }
    });
  }

  setConnected = (value: boolean) => {
    this.connected = value;
  };

  setLastUpdated = (value: number) => {
    this.lastUpdated = value;
  };

  onDeleteImageProfile = async () => {
    const email = this.email;
    if (email) {
      const storage = getStorage();

      // Create a reference to the file to delete
      const desertRef = storageRef(
        storage,
        GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH(email)
      );

      // Delete the file
      await deleteObject(desertRef);
    }
  };
}

// export const GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH_URI = (
//   email: string,
//   token: string
// ) => {
//   return `https://firebasestorage.googleapis.com/v0/b/${
//     firebaseConfig.storageBucket
//   }/o/${encodeURIComponent(
//     GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH(email)
//   )}?alt=media&token=${token}`;
// };
