import './firebaseInit';
import firebase from 'firebase/app';
import 'firebase/firestore';
import { deferred } from './deferred';
import { trackEvent } from './analytics';
import { log } from './utils';

(() => {
	const FAUX_DELAY = 1;

	var db;
	var dbPromise;

	var local = {
		get: (obj, cb) => {
			const retVal = {};
			if (typeof obj === 'string') {
				retVal[obj] = JSON.parse(window.localStorage.getItem(obj));
				setTimeout(() => cb(retVal), FAUX_DELAY);
			} else {
				Object.keys(obj).forEach(key => {
					const val = window.localStorage.getItem(key);
					retVal[key] =
						val === undefined || val === null ? obj[key] : JSON.parse(val);
				});
				setTimeout(() => cb(retVal), FAUX_DELAY);
			}
		},
		set: (obj, cb) => {
			Object.keys(obj).forEach(key => {
				window.localStorage.setItem(key, JSON.stringify(obj[key]));
			});
			/* eslint-disable consistent-return */
			setTimeout(() => {
				if (cb) {
					return cb();
				}
			}, FAUX_DELAY);
			/* eslint-enable consistent-return */
		},
		remove: (key, cb) => {
			window.localStorage.removeItem(key);
			setTimeout(() => cb(), FAUX_DELAY);
		}
	};
	const dbLocalAlias = chrome && chrome.storage ? chrome.storage.local : local;
	const dbSyncAlias = chrome && chrome.storage ? chrome.storage.sync : local;

	async function getDb() {
		if (dbPromise) {
			return dbPromise;
		}
		log('Initializing firestore');
		dbPromise = new Promise((resolve, reject) => {
			if (db) {
				return resolve(db);
			}
			return firebase
				.firestore()
				.enablePersistence()
				.then(function() {
					// Initialize Cloud Firestore through firebase
					db = firebase.firestore();
					// const settings = {
					// 	timestampsInSnapshots: true
					// };
					// db.settings(settings);
					log('firebase db ready', db);
					resolve(db);
				})
				.catch(function(err) {
					reject(err.code);
					if (err.code === 'failed-precondition') {
						// Multiple tabs open, persistence can only be enabled
						// in one tab at a a time.
						alert(
							"Opening Web Maker web app in multiple tabs isn't supported at present and it seems like you already have it opened in another tab. Please use in one tab."
						);
						trackEvent('fn', 'multiTabError');
					} else if (err.code === 'unimplemented') {
						// The current browser does not support all of the
						// features required to enable persistence
						// ...
					}
				});
		});
		return dbPromise;
	}

	async function getUserLastSeenVersion() {
		const d = deferred();
		// Will be chrome.storage.sync in extension environment,
		// otherwise will fallback to localstorage
		dbSyncAlias.get(
			{
				lastSeenVersion: ''
			},
			result => {
				d.resolve(result.lastSeenVersion);
			}
		);
		return d.promise;
		// Might consider getting actual value from remote db.
		// Not critical right now.
	}

	async function setUserLastSeenVersion(version) {
		// Setting the `lastSeenVersion` in localStorage(sync for extension) always
		// because next time we need to fetch it irrespective of the user being
		// logged in or out quickly from local storage.
		dbSyncAlias.set(
			{
				lastSeenVersion: version
			},
			function() {}
		);
		if (window.user) {
			const remoteDb = await getDb();
			remoteDb.doc(`users/${window.user.uid}`).update({
				lastSeenVersion: version
			});
		}
	}

	async function getUser(userId) {
		const remoteDb = await getDb();
		return remoteDb
			.doc(`users/${userId}`)
			.get()
			.then(doc => {
				if (!doc.exists)
					return remoteDb.doc(`users/${userId}`).set(
						{},
						{
							merge: true
						}
					);
				const user = doc.data();
				Object.assign(window.user, user);
				return user;
			});
	}

	// Fetch user settings.
	// This isn't hitting the remote db because remote settings
	// get fetch asynchronously (in user/) and update the envioronment.
	function getSettings(defaultSettings) {
		const d = deferred();
		// Will be chrome.storage.sync in extension environment,
		// otherwise will fallback to localstorage
		dbSyncAlias.get(defaultSettings, result => {
			d.resolve(result);
		});
		return d.promise;
	}

	window.db = {
		getDb,
		getUser,
		getUserLastSeenVersion,
		setUserLastSeenVersion,
		getSettings,
		local: dbLocalAlias,
		sync: dbSyncAlias
	};
})();
