import { InteractionManager } from 'react-native';
import semver from 'semver';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
import { orderBy } from 'lodash';

import database from '../database';
import log from '../../utils/log';
import reduxStore from '../createStore';
import protectedFunction from './helpers/protectedFunction';

const getUpdatedSince = (allRecords) => {
	try {
		if (!allRecords.length) {
			return null;
		}
		const ordered = orderBy(allRecords.filter(item => item._updatedAt !== null), ['_updatedAt'], ['desc']);
		return ordered && ordered[0]._updatedAt.toISOString();
	} catch (e) {
		log(e);
	}
	return null;
};

const updatePermissions = async({ update = [], remove = [], allRecords }) => {
	if (!((update && update.length) || (remove && remove.length))) {
		return;
	}
	const db = database.active;
	const permissionsCollection = db.collections.get('permissions');

	// filter permissions
	let permissionsToCreate = [];
	let permissionsToUpdate = [];
	let permissionsToDelete = [];

	// Create or update
	if (update && update.length) {
		permissionsToCreate = update.filter(i1 => !allRecords.find(i2 => i1._id === i2.id));
		permissionsToUpdate = allRecords.filter(i1 => update.find(i2 => i1.id === i2._id));
		permissionsToCreate = permissionsToCreate.map(permission => permissionsCollection.prepareCreate(protectedFunction((p) => {
			p._raw = sanitizedRaw({ id: permission._id }, permissionsCollection.schema);
			Object.assign(p, permission);
		})));
		permissionsToUpdate = permissionsToUpdate.map((permission) => {
			const newPermission = update.find(p => p._id === permission.id);
			return permission.prepareUpdate(protectedFunction((p) => {
				Object.assign(p, newPermission);
			}));
		});
	}

	// Delete
	if (remove && remove.length) {
		permissionsToDelete = allRecords.filter(i1 => remove.find(i2 => i1.id === i2._id));
		permissionsToDelete = permissionsToDelete.map(permission => permission.prepareDestroyPermanently());
	}

	const batch = [
		...permissionsToCreate,
		...permissionsToUpdate,
		...permissionsToDelete
	];

	try {
		await db.action(async() => {
			await db.batch(...batch);
		});
	} catch (e) {
		log(e);
	}
};

export default function() {
	return new Promise(async(resolve) => {
		try {
			const serverVersion = reduxStore.getState().server.version;
			const db = database.active;
			const permissionsCollection = db.collections.get('permissions');
			const allRecords = await permissionsCollection.query().fetch();

			// if server version is lower than 0.73.0, fetches from old api
			if (semver.lt(serverVersion, '0.73.0')) {
				// RC 0.66.0
				const result = await this.sdk.get('permissions.list');
				if (!result.success) {
					return resolve();
				}
				InteractionManager.runAfterInteractions(async() => {
					await updatePermissions({ update: result.permissions, allRecords });
					return resolve();
				});
			} else {
				const params = {};
				const updatedSince = await getUpdatedSince(allRecords);
				if (updatedSince) {
					params.updatedSince = updatedSince;
				}
				// RC 0.73.0
				const result = await this.sdk.get('permissions.listAll', params);

				if (!result.success) {
					return resolve();
				}

				InteractionManager.runAfterInteractions(async() => {
					await updatePermissions({ update: result.update, remove: result.delete, allRecords });
					return resolve();
				});
			}
		} catch (e) {
			log(e);
			return resolve();
		}
	});
}