import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
import { ReactiveVar } from 'meteor/reactive-var';
import { Random } from 'meteor/random';
import { Tracker } from 'meteor/tracker';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import _ from 'underscore';
import s from 'underscore.string';
import toastr from 'toastr';

import { settings } from '../../settings';
import { SideNav, modal } from '../../ui-utils';
import { t, handleError } from '../../utils';
import { CachedCollection } from '../../ui-cached-collection';

const TempSettings = new Mongo.Collection(null);

const getDefaultSetting = function(settingId) {
	return settings.collectionPrivate.findOne({
		_id: settingId,
	});
};

const setFieldValue = function(settingId, value, type, editor) {
	const input = $('.page-settings').find(`[name="${ settingId }"]`);
	switch (type) {
		case 'boolean':
			$('.page-settings').find(`[name="${ settingId }"][value="${ Number(value) }"]`).prop('checked', true).change();
			break;
		case 'code':
			input.next()[0].CodeMirror.setValue(value);
			break;
		case 'color':
			editor = value && value[0] === '#' ? 'color' : 'expression';
			input.parents('.horizontal').find('select[name="color-editor"]').val(editor).change();
			input.val(value).change();
			break;
		case 'roomPick':
			const selectedRooms = Template.instance().selectedRooms.get();
			selectedRooms[settingId] = value;
			Template.instance().selectedRooms.set(selectedRooms);
			TempSettings.update({ _id: settingId }, { $set: { value, changed: JSON.stringify(settings.collectionPrivate.findOne(settingId).value) !== JSON.stringify(value) } });
			break;
		default:
			input.val(value).change();
	}
};

Template.admin.onCreated(function() {
	if (settings.cachedCollectionPrivate == null) {
		settings.cachedCollectionPrivate = new CachedCollection({
			name: 'private-settings',
			eventType: 'onLogged',
			useCache: false,
		});
		settings.collectionPrivate = settings.cachedCollectionPrivate.collection;
		settings.cachedCollectionPrivate.init();
	}
	this.selectedRooms = new ReactiveVar({});
	settings.collectionPrivate.find().observe({
		added: (data) => {
			const selectedRooms = this.selectedRooms.get();
			if (data.type === 'roomPick') {
				selectedRooms[data._id] = data.value;
				this.selectedRooms.set(selectedRooms);
			}
			TempSettings.insert(data);
		},
		changed: (data) => {
			const selectedRooms = this.selectedRooms.get();
			if (data.type === 'roomPick') {
				selectedRooms[data._id] = data.value;
				this.selectedRooms.set(selectedRooms);
			}
			TempSettings.update(data._id, data);
		},
		removed: (data) => {
			const selectedRooms = this.selectedRooms.get();
			if (data.type === 'roomPick') {
				delete selectedRooms[data._id];
				this.selectedRooms.set(selectedRooms);
			}
			TempSettings.remove(data._id);
		},
	});
});

Template.admin.onDestroyed(function() {
	TempSettings.remove({});
});

Template.admin.helpers({
	languages() {
		const languages = TAPi18n.getLanguages();

		const result = Object.entries(languages)
			.map(([key, language]) => ({ ...language, key: key.toLowerCase() }))
			.sort((a, b) => a.key - b.key);

		result.unshift({
			name: 'Default',
			en: 'Default',
			key: '',
		});

		return result;
	},
	isAppLanguage(key) {
		const languageKey = settings.get('Language');
		return typeof languageKey === 'string' && languageKey.toLowerCase() === key;
	},
	group() {
		const groupId = FlowRouter.getParam('group');
		const group = settings.collectionPrivate.findOne({
			_id: groupId,
			type: 'group',
		});
		if (!group) {
			return;
		}
		const rcSettings = settings.collectionPrivate.find({ group: groupId }, { sort: { section: 1, sorter: 1, i18nLabel: 1 } }).fetch();
		const sections = {};

		Object.keys(rcSettings).forEach((key) => {
			const setting = rcSettings[key];
			let i18nDefaultQuery;
			if (setting.i18nDefaultQuery != null) {
				if (_.isString(setting.i18nDefaultQuery)) {
					i18nDefaultQuery = JSON.parse(setting.i18nDefaultQuery);
				} else {
					i18nDefaultQuery = setting.i18nDefaultQuery;
				}
				if (!_.isArray(i18nDefaultQuery)) {
					i18nDefaultQuery = [i18nDefaultQuery];
				}
				Object.keys(i18nDefaultQuery).forEach((key) => {
					const item = i18nDefaultQuery[key];
					if (settings.collectionPrivate.findOne(item) != null) {
						setting.value = TAPi18n.__(`${ setting._id }_Default`);
					}
				});
			}
			const settingSection = setting.section || '';
			if (sections[settingSection] == null) {
				sections[settingSection] = [];
			}
			sections[settingSection].push(setting);
		});

		group.sections = Object.keys(sections).map((key) => {
			const value = sections[key];
			return {
				section: key,
				settings: value,
			};
		});
		return group;
	},
	i18nDefaultValue() {
		return TAPi18n.__(`${ this._id }_Default`);
	},
	isDisabled() {
		let enableQuery;
		if (this.blocked) {
			return {
				disabled: 'disabled',
			};
		}
		if (this.enableQuery == null) {
			return {};
		}
		if (_.isString(this.enableQuery)) {
			enableQuery = JSON.parse(this.enableQuery);
		} else {
			enableQuery = this.enableQuery;
		}
		if (!_.isArray(enableQuery)) {
			enableQuery = [enableQuery];
		}
		let found = 0;

		Object.keys(enableQuery).forEach((key) => {
			const item = enableQuery[key];
			if (TempSettings.findOne(item) != null) {
				found++;
			}
		});
		if (found === enableQuery.length) {
			return {};
		}
		return {
			disabled: 'disabled',
		};
	},
	isReadonly() {
		if (this.readonly === true) {
			return {
				readonly: 'readonly',
			};
		}
	},
	canAutocomplete() {
		if (this.autocomplete === false) {
			return {
				autocomplete: 'off',
			};
		}
	},
	hasChanges(section) {
		const group = FlowRouter.getParam('group');
		const query = {
			group,
			changed: true,
		};
		if (section != null) {
			if (section === '') {
				query.$or = [
					{
						section: '',
					}, {
						section: {
							$exists: false,
						},
					},
				];
			} else {
				query.section = section;
			}
		}
		return TempSettings.find(query).count() > 0;
	},
	isSettingChanged(id) {
		return TempSettings.findOne({
			_id: id,
		}, {
			fields: {
				changed: 1,
			},
		}).changed;
	},
	translateSection(section) {
		if (section.indexOf(':') > -1) {
			return section;
		}
		return t(section);
	},
	label() {
		const label = this.i18nLabel || this._id;
		if (label) {
			return TAPi18n.__(label);
		}
	},
	description() {
		let description;
		if (this.i18nDescription) {
			description = TAPi18n.__(this.i18nDescription);
		}
		if ((description != null) && description !== this.i18nDescription) {
			return description;
		}
	},
	sectionIsCustomOAuth(section) {
		return /^Custom OAuth:\s.+/.test(section);
	},
	callbackURL(section) {
		const id = s.strRight(section, 'Custom OAuth: ').toLowerCase();
		return Meteor.absoluteUrl(`_oauth/${ id }`);
	},
	relativeUrl(url) {
		return Meteor.absoluteUrl(url);
	},
	selectedOption(_id, val) {
		const option = settings.collectionPrivate.findOne({ _id });
		return option && option.value === val;
	},
	random() {
		return Random.id();
	},
	getEditorOptions(readOnly = false) {
		return {
			lineNumbers: true,
			mode: this.code || 'javascript',
			gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
			foldGutter: true,
			matchBrackets: true,
			autoCloseBrackets: true,
			matchTags: true,
			showTrailingSpace: true,
			highlightSelectionMatches: true,
			readOnly,
		};
	},
	setEditorOnBlur(_id) {
		Meteor.defer(function() {
			if (!$(`.code-mirror-box[data-editor-id="${ _id }"] .CodeMirror`)[0]) {
				return;
			}
			const codeMirror = $(`.code-mirror-box[data-editor-id="${ _id }"] .CodeMirror`)[0].CodeMirror;
			if (codeMirror.changeAdded === true) {
				return;
			}
			const onChange = function() {
				const value = codeMirror.getValue();
				TempSettings.update({ _id }, { $set: { value, changed: settings.collectionPrivate.findOne(_id).value !== value } });
			};
			const onChangeDelayed = _.debounce(onChange, 500);
			codeMirror.on('change', onChangeDelayed);
			codeMirror.changeAdded = true;
		});
	},
	assetAccept(fileConstraints) {
		if (fileConstraints.extensions && fileConstraints.extensions.length) {
			return `.${ fileConstraints.extensions.join(', .') }`;
		}
	},
	autocompleteRoom() {
		return {
			limit: 10,
			// inputDelay: 300
			rules: [
				{
					// @TODO maybe change this 'collection' and/or template
					collection: 'CachedChannelList',
					subscription: 'channelAndPrivateAutocomplete',
					field: 'name',
					template: Template.roomSearch,
					noMatchTemplate: Template.roomSearchEmpty,
					matchAll: true,
					selector(match) {
						return {
							name: match,
						};
					},
					sort: 'name',
				},
			],
		};
	},
	selectedRooms() {
		return Template.instance().selectedRooms.get()[this._id] || [];
	},
	getColorVariable(color) {
		return color.replace(/theme-color-/, '@');
	},
	showResetButton() {
		const setting = TempSettings.findOne({ _id: this._id }, { fields: { value: 1, packageValue: 1 } });
		return !this.disableReset && !this.readonly && this.type !== 'asset' && setting.value !== setting.packageValue && !this.blocked;
	},
});

Template.admin.events({
	'change .input-monitor, keyup .input-monitor': _.throttle(function(e) {
		let value = s.trim($(e.target).val());
		switch (this.type) {
			case 'int':
				value = parseInt(value);
				break;
			case 'boolean':
				value = value === '1';
				break;
			case 'color':
				$(e.target).siblings('.colorpicker-swatch').css('background-color', value);
		}
		TempSettings.update({
			_id: this._id,
		}, {
			$set: {
				value,
				changed: settings.collectionPrivate.findOne(this._id).value !== value,
			},
		});
	}, 500),
	'change select[name=color-editor]'(e) {
		const value = s.trim($(e.target).val());
		TempSettings.update({ _id: this._id }, { $set: { editor: value } });
		settings.collectionPrivate.update({ _id: this._id }, { $set: { editor: value } });
	},
	'click .rc-header__section-button .discard'() {
		const group = FlowRouter.getParam('group');
		const query = {
			group,
			changed: true,
		};
		const rcSettings = TempSettings.find(query, {
			fields: { _id: 1, value: 1, packageValue: 1 },
		}).fetch();
		rcSettings.forEach(function(setting) {
			const oldSetting = settings.collectionPrivate.findOne({ _id: setting._id }, { fields: { value: 1, type: 1, editor: 1 } });
			setFieldValue(setting._id, oldSetting.value, oldSetting.type, oldSetting.editor);
		});
	},
	'click .reset-setting'(e) {
		e.preventDefault();
		let settingId = $(e.target).data('setting');
		if (typeof settingId === 'undefined') {
			settingId = $(e.target).parent().data('setting');
		}
		const defaultValue = getDefaultSetting(settingId);
		setFieldValue(settingId, defaultValue.packageValue, defaultValue.type, defaultValue.editor);
	},
	'click .reset-group'(e) {
		let rcSettings;
		e.preventDefault();
		const group = FlowRouter.getParam('group');
		const section = $(e.target).data('section');
		if (section === '') {
			rcSettings = TempSettings.find({ group, section: { $exists: false } }, { fields: { _id: 1 } }).fetch();
		} else {
			rcSettings = TempSettings.find({ group, section }, { fields: { _id: 1 } }).fetch();
		}
		rcSettings.forEach(function(setting) {
			const defaultValue = getDefaultSetting(setting._id);
			setFieldValue(setting._id, defaultValue.packageValue, defaultValue.type, defaultValue.editor);
			TempSettings.update({ _id: setting._id }, {
				$set: {
					value: defaultValue.packageValue,
					changed: settings.collectionPrivate.findOne(setting._id).value !== defaultValue.packageValue,
				},
			});
		});
	},
	'click .rc-header__section-button .save'() {
		const group = FlowRouter.getParam('group');
		const query = { group, changed: true };
		const rcSettings = TempSettings.find(query, { fields: { _id: 1, value: 1, editor: 1 } }).fetch() || [];
		if (rcSettings.length === 0) {
			return;
		}

		settings.batchSet(rcSettings, (err) => {
			if (err) {
				return handleError(err);
			}

			TempSettings.update({ changed: true }, { $unset: { changed: 1 } });

			if (rcSettings.some(({ _id }) => _id === 'Language')) {
				const lng = Meteor.user().language
					|| rcSettings.filter(({ _id }) => _id === 'Language').shift().value
					|| 'en';
				return TAPi18n._loadLanguage(lng).then(() => toastr.success(TAPi18n.__('Settings_updated', { lng })));
			}
			toastr.success(TAPi18n.__('Settings_updated'));
		});
	},
	'click .rc-header__section-button .refresh-clients'() {
		Meteor.call('refreshClients', function() {
			toastr.success(TAPi18n.__('Clients_will_refresh_in_a_few_seconds'));
		});
	},
	'click .rc-header__section-button .add-custom-oauth'() {
		const config = {
			title: TAPi18n.__('Add_custom_oauth'),
			text: TAPi18n.__('Give_a_unique_name_for_the_custom_oauth'),
			type: 'input',
			showCancelButton: true,
			closeOnConfirm: true,
			inputPlaceholder: TAPi18n.__('Custom_oauth_unique_name'),
		};
		modal.open(config, function(inputValue) {
			if (inputValue === false) {
				return false;
			}
			if (inputValue === '') {
				modal.showInputError(TAPi18n.__('Name_cant_be_empty'));
				return false;
			}
			Meteor.call('addOAuthService', inputValue, function(err) {
				if (err) {
					handleError(err);
				}
			});
		});
	},
	'click .rc-header__section-button .refresh-oauth'() {
		toastr.info(TAPi18n.__('Refreshing'));
		return Meteor.call('refreshOAuthService', function(err) {
			if (err) {
				return handleError(err);
			}
			return toastr.success(TAPi18n.__('Done'));
		});
	},
	'click .remove-custom-oauth'() {
		const name = this.section.replace('Custom OAuth: ', '');
		const config = {
			title: TAPi18n.__('Are_you_sure'),
			type: 'warning',
			showCancelButton: true,
			confirmButtonColor: '#DD6B55',
			confirmButtonText: TAPi18n.__('Yes_delete_it'),
			cancelButtonText: TAPi18n.__('Cancel'),
			closeOnConfirm: true,
		};
		modal.open(config, function() {
			Meteor.call('removeOAuthService', name);
		});
	},
	'click .delete-asset'() {
		Meteor.call('unsetAsset', this.asset);
	},
	'change input[type=file]'(ev) {
		const e = ev.originalEvent || ev;
		let { files } = e.target;
		if (!files || files.length === 0) {
			if (e.dataTransfer && e.dataTransfer.files) {
				files = e.dataTransfer.files;
			} else {
				files = [];
			}
		}

		Object.keys(files).forEach((key) => {
			const blob = files[key];
			toastr.info(TAPi18n.__('Uploading_file'));
			const reader = new FileReader();
			reader.readAsBinaryString(blob);
			reader.onloadend = () => Meteor.call('setAsset', reader.result, blob.type, this.asset, function(err) {
				if (err != null) {
					handleError(err);
					console.log(err);
					return;
				}
				return toastr.success(TAPi18n.__('File_uploaded'));
			});
		});
	},
	'click .expand'(e) {
		const sectionTitle = e.currentTarget;
		const section = sectionTitle.closest('.section');
		const button = sectionTitle.querySelector('button');
		const i = button.querySelector('i');

		sectionTitle.classList.remove('expand');
		sectionTitle.classList.add('collapse');
		section.classList.remove('section-collapsed');
		button.setAttribute('title', TAPi18n.__('Collapse'));
		i.className = 'icon-angle-up';

		$('.CodeMirror').each(function(index, codeMirror) {
			codeMirror.CodeMirror.refresh();
		});
	},
	'click .collapse'(e) {
		const sectionTitle = e.currentTarget;
		const section = sectionTitle.closest('.section');
		const button = sectionTitle.querySelector('button');
		const i = button.querySelector('i');

		sectionTitle.classList.remove('collapse');
		sectionTitle.classList.add('expand');
		section.classList.add('section-collapsed');
		button.setAttribute('title', TAPi18n.__('Expand'));
		i.className = 'icon-angle-down';
	},
	'click button.action'() {
		if (this.type !== 'action') {
			return;
		}
		Meteor.call(this.value, function(err, data) {
			if (err != null) {
				err.details = _.extend(err.details || {}, {
					errorTitle: 'Error',
				});
				handleError(err);
				return;
			}
			const args = [data.message].concat(data.params);
			toastr.success(TAPi18n.__.apply(TAPi18n, args), TAPi18n.__('Success'));
		});
	},
	'click .button-fullscreen'() {
		const codeMirrorBox = $(`.code-mirror-box[data-editor-id="${ this._id }"]`);
		codeMirrorBox.addClass('code-mirror-box-fullscreen content-background-color');
		codeMirrorBox.find('.CodeMirror')[0].CodeMirror.refresh();
	},
	'click .button-restore'() {
		const codeMirrorBox = $(`.code-mirror-box[data-editor-id="${ this._id }"]`);
		codeMirrorBox.removeClass('code-mirror-box-fullscreen content-background-color');
		codeMirrorBox.find('.CodeMirror')[0].CodeMirror.refresh();
	},
	'autocompleteselect .autocomplete'(event, instance, doc) {
		const selectedRooms = instance.selectedRooms.get();
		selectedRooms[this.id] = (selectedRooms[this.id] || []).concat(doc);
		instance.selectedRooms.set(selectedRooms);
		const value = selectedRooms[this.id];
		TempSettings.update({ _id: this.id }, { $set: { value, changed: JSON.stringify(settings.collectionPrivate.findOne(this.id).value) !== JSON.stringify(value) } });
		event.currentTarget.value = '';
		event.currentTarget.focus();
	},
	'click .remove-room'(event, instance) {
		const docId = this._id;
		const settingId = event.currentTarget.getAttribute('data-setting');
		const selectedRooms = instance.selectedRooms.get();
		selectedRooms[settingId] = _.reject(selectedRooms[settingId] || [], function(setting) {
			return setting._id === docId;
		});
		instance.selectedRooms.set(selectedRooms);
		const value = selectedRooms[settingId];
		TempSettings.update({ _id: settingId }, {
			$set: {
				value,
				changed: JSON.stringify(settings.collectionPrivate.findOne(settingId).value) !== JSON.stringify(value),
			},
		});
	},
});

Template.admin.onRendered(function() {
	Tracker.afterFlush(function() {
		SideNav.setFlex('adminFlex');
		SideNav.openFlex();
	});
	Tracker.autorun(function() {
		const hasColor = TempSettings.find({
			group: FlowRouter.getParam('group'),
			type: 'color',
		}, { fields: { _id: 1, editor: 1 } }).fetch().length;
		if (hasColor) {
			Meteor.setTimeout(function() {
				$('.colorpicker-input').each(function(index, el) {
					if (!el._jscLinkedInstance) {
						new jscolor(el); //eslint-disable-line
					}
				});
			}, 400);
		}
	});
});
