import { deferred } from './deferred';
import { log } from 'util';

export const itemService = {
	async getItem(id) {
		var remoteDb = await window.db.getDb();
		return remoteDb
			.doc(`items/${id}`)
			.get()
			.then(doc => {
				return doc.data();
			});
	},
	async getUserItemIds() {
		if (window.user) {
			return new Promise(resolve => {
				resolve(window.user.items || {});
			});
		}
		var remoteDb = await window.db.getDb();
		return remoteDb
			.doc(`users/${window.user.uid}`)
			.get()
			.then(doc => {
				if (!doc.exists) {
					return {};
				}
				return doc.data().items;
			});
	},

	async getAllItems() {
		var t = Date.now();
		var d = deferred();
		let itemIds = await this.getUserItemIds();
		itemIds = Object.getOwnPropertyNames(itemIds || {});
		log('itemids', itemIds);

		if (!itemIds.length) {
			d.resolve([]);
		}
		var remoteDb = await window.db.getDb();
		const items = [];
		remoteDb
			.collection('items')
			.where('createdBy', '==', window.user.uid)
			.onSnapshot(
				function(querySnapshot) {
					querySnapshot.forEach(function(doc) {
						items.push(doc.data());
					});
					log('Items fetched in ', Date.now() - t, 'ms');

					d.resolve(items);
				},
				function() {
					d.resolve([]);
				}
			);
		return d.promise;
	},

	async setUser() {
		const remoteDb = await window.db.getDb();
		return remoteDb.doc(`users/${window.user.uid}`).set({
			items: {}
		});
	},

	async setItem(id, item) {
		const d = deferred();
		var remotePromise;
		// TODO: check why we need to save locally always?
		const obj = {
			[id]: item
		};
		db.local.set(obj, () => {
			// Is extension OR is app but logged out OR is logged in but offline
			// If logged in but offline, resolve immediately so
			// that you see the feedback msg immediately and not wait for
			// later sync.
			if (window.IS_EXTENSION || !window.user || !navigator.onLine) {
				d.resolve();
			}
		});

		// If `id` is `code`, this is a call on unloadbefore to save the last open thing.
		// Do not presist that on remote.
		if (id === 'code') {
			// No deferred required here as this gets called on unloadbefore
			return false;
		}
		if (window.user) {
			var remoteDb = await window.db.getDb();
			log(`Starting to save item ${id}`);
			item.createdBy = window.user.uid;
			remotePromise = remoteDb
				.collection('items')
				.doc(id)
				.set(item, {
					merge: true
				})
				.then(arg => {
					log('Document written', arg);
					d.resolve();
				})
				.catch(d.reject);
		}

		return window.user && navigator.onLine ? remotePromise : d.promise;
	},

	/**
	 * Saves the passed items in the database.
	 * @param {Array} items to be saved in DB
	 */
	saveItems(items) {
		var d = deferred();
		// When not logged in
		if (!window.user) {
			// save new items
			window.db.local.set(items, d.resolve);
			// Push in new item IDs
			window.db.local.get(
				{
					items: {}
				},
				function(result) {
					/* eslint-disable guard-for-in */
					for (var id in items) {
						result.items[id] = true;
					}
					window.db.local.set({
						items: result.items
					});
					/* eslint-enable guard-for-in */
				}
			);
		} else {
			window.db.getDb().then(remoteDb => {
				const batch = remoteDb.batch();
				/* eslint-disable guard-for-in */
				for (var id in items) {
					items[id].createdBy = window.user.uid;
					batch.set(remoteDb.doc(`items/${id}`), items[id]);
					batch.update(remoteDb.doc(`users/${window.user.uid}`), {
						[`items.${id}`]: true
					});
					// Set these items on our cached user object too
					window.user.items = window.user.items || {};
					window.user.items[id] = true;
				}
				batch.commit().then(d.resolve);
				/* eslint-enable guard-for-in */
			});
		}
		return d.promise;
	},

	async removeItem(id) {
		// When not logged in
		if (!window.user) {
			var d = deferred();
			window.db.local.remove(id, d.resolve);
			return d.promise;
		}
		const remoteDb = await window.db.getDb();
		log(`Starting to save item ${id}`);
		return remoteDb
			.collection('items')
			.doc(id)
			.delete()
			.then(arg => {
				log('Document removed', arg);
			})
			.catch(error => log(error));
	},

	async setItemForUser(itemId) {
		// When not logged in
		if (!window.user) {
			return window.db.local.get(
				{
					items: {}
				},
				function(result) {
					result.items[itemId] = true;
					window.db.local.set({
						items: result.items
					});
				}
			);
		}
		const remoteDb = await window.db.getDb();
		return remoteDb
			.collection('users')
			.doc(window.user.uid)
			.update({
				[`items.${itemId}`]: true
			})
			.then(arg => {
				log(`Item ${itemId} set for user`, arg);
				window.user.items = window.user.items || {};
				window.user.items[itemId] = true;
			})
			.catch(error => log(error));
	},

	async unsetItemForUser(itemId) {
		// When not logged in
		if (!window.user) {
			return window.db.local.get(
				{
					items: {}
				},
				function(result) {
					delete result.items[itemId];
					window.db.local.set({
						items: result.items
					});
				}
			);
		}
		const remoteDb = await window.db.getDb();
		return remoteDb
			.collection('users')
			.doc(window.user.uid)
			.update({
				[`items.${itemId}`]: firebase.firestore.FieldValue.delete()
			})
			.then(arg => {
				delete window.user.items[itemId];
				log(`Item ${itemId} unset for user`, arg);
			})
			.catch(error => log(error));
	}
};
