/* =================
   SELECTED FIELD
   ================= */

import { Entity, Field, FieldSettings, Rule } from '../../utils/_interfaces';
import ExportSettings from '../../config/_export-settings';
import FiltersBuilder from './_filters-builder';
import Globals from './_globals';
import { Switcher } from '../../../../../../atum-stock-manager-for-woocommerce/assets/js/src/components/_switcher';

export default class SelectedField {
	
	$elem: JQuery = null;
	filtersBuilder: FiltersBuilder;
	$settingsSection: JQuery;
	$fieldPosition: JQuery;
	$fieldVisibility: JQuery;
	$settingsInput: JQuery;
	
	constructor(
		public field: Field,
		public entity: Entity,
		private $fieldSelector: JQuery,
		private globals: Globals,
		private settings: ExportSettings
	) {
		
		this.$elem = $(this.globals.$selectionSection.find('#selected-field-tmpl').html());
		this.filtersBuilder = new FiltersBuilder( this.$elem.find('.selected-field--filters'), this.field.type, this.settings, this.globals );
		this.$settingsSection = this.$elem.find('.selected-field--settings');
		this.$fieldPosition = this.$settingsSection.find('.field-position');
		this.$fieldVisibility = this.$settingsSection.find('.field-visibility');
		this.$settingsInput = this.$settingsSection.children('input:hidden');
		
		this.prepareField();
		
		// Add the instance to the entity selector field and to the selected field.
		this.$fieldSelector.data('selected-field', this);
		this.$elem.data('selected-field', this);
	}
	
	/**
	 * Prepare the selected field for the DOM
	 */
	prepareField() {
		
		this.$elem.attr('data-field', this.field.name); // We need the data attribute to be able to use it as a selector.
		this.$elem.attr('data-entity', this.entity.name);
		this.$elem.find('.selected-field--title').html(`
			<span class="entity-label atum-tooltip" title="${ this.settings.get( this.entity.isMain ? 'mainEntity' : 'subentities' ) }">${ this.entity.title }</span>
			<span class="field-label atum-tooltip" title="${ this.field.label ? `${ this.field.label } (${ this.field.name })` : this.field.name }">${ this.field.label || this.field.name }</span>
		`);
		
		this.bindEvents();
		
		// Add the default values coming from a pre-saved template (if any).
		if (this.field.settings) {
			
			for (const setting in this.field.settings) {
				
				const $input: JQuery = this.$settingsSection.find(`[name="${ setting }"]`);
				
				if ( $input.is(':checkbox') ) {
					$input.prop('checked', 'yes' === this.field.settings[setting] ? true : false).change();
				}
				else {
					$input.val(this.field.settings[setting]);
				}
				
			}
			
			this.$settingsInput.val( JSON.stringify(this.field.settings) );
			
		}
		
		this.$settingsSection.find('input[name="column_name"]').attr('placeholder', this.field.name);
		
		if (this.field.filters) {
			
			this.field.filters.forEach( (filterRule: Rule) => {
				this.filtersBuilder.addRule(filterRule.condition, filterRule.value);
			});
		
		}
		
		// Add select2.
		this.globals.enhancedSelect.doSelect2(this.$elem.find('.atum-select2'));
		
		// Add switchers
		Switcher.doSwitchers('.js-switch', {}, this.$elem);
		
		// Add tooltips.
		this.globals.tooltip.addTooltips(this.$elem);
		
	}
	
	bindEvents() {
	
		this.$elem
		
			// Field filters and settings sections togglers.
			.on('click', '.field-filters, .field-settings', (evt: JQueryEventObject) => this.toggleField( $(evt.currentTarget) ) )
			
			// Remove field button.
			.on('click', '.field-remove', () => this.remove() )
		
			// Rearrange the field positions when changing the position select.
			.on('change', '.field-position', (evt: JQueryEventObject) =>  {
				this.maybeAddDefaultSettings();
				this.field.settings.position = parseInt( $(evt.currentTarget).val() );
				this.adjustFieldPosition();
				this.globals.rearrangePositionSelects(true);
			})
		
			// Add/Remove the visibility icon when toggling the switcher.
			.on('change', '.field-visibility', (evt: JQueryEventObject) => this.maybeAddVisibilityIcon( $(evt.currentTarget).is(':checked') ) )
		
			// Update the settings input when changing the inputs.
			.on('change', ':input', () => this.updateSettingsInput() );
		
		// Do actions when the rules input gets updated.
		this.filtersBuilder.$elem.on('atum-export-rules-input-updated', (evt: JQueryEventObject, rules: Rule[]) => {
			
			// Update the summary.
			this.globals.summary.maybeCreateSummary();
			
			// Update the field filters icon status.
			const $fieldFiltersButton: JQuery = this.$elem.find('i.field-filters');
			
			if (rules.length) {
				$fieldFiltersButton.addClass('with-filters');
			}
			else {
				$fieldFiltersButton.removeClass('with-filters');
			}
			
		});
		
	}
	
	/**
	 * Remove the current field
	 *
	 * @param {boolean} force
	 */
	remove(force: boolean = false) {
		
		if (force === true) {
			
			this.$elem.remove();
			this.$fieldSelector.removeClass('selected').removeData('selected-field');
			this.globals.maybeShowDroppingZone();
			this.globals.summary.maybeCreateSummary();
			this.globals.rearrangePositionSelects();
			
			return;
		}
		
		// Warn the user about unsaved data.
		this.globals.swal({
			title              : this.settings.get('areYouSure'),
			text               : this.settings.get('removeField'),
			type               : 'warning',
			showCancelButton   : true,
			confirmButtonText  : this.settings.get('continue'),
			cancelButtonText   : this.settings.get('cancel'),
			reverseButtons     : true,
			allowOutsideClick  : false
		})
		.then( () =>  {
			
			this.$elem.remove();
			this.$fieldSelector.removeClass('selected').removeData('selected-field');
			this.globals.maybeShowDroppingZone();
			this.globals.summary.maybeCreateSummary();
			this.globals.rearrangePositionSelects();
			
		} )
		.catch(this.globals.swal.noop);
		
	}
	
	/**
	 * Toggle the field settings/filters sections
	 *
	 * @param {JQuery} $fieldAction
	 */
	toggleField($fieldAction: JQuery) {
		
		const $field: JQuery = $fieldAction.closest('.selected-field');
		
		$fieldAction.siblings('.active').removeClass('active');
		
		if ($fieldAction.hasClass('field-filters')) {
			$field.find('.selected-field--settings').hide();
			$field.find('.selected-field--filters').show();
		}
		else {
			$field.find('.selected-field--filters').hide();
			$field.find('.selected-field--settings').show();
		}
		
		if ($fieldAction.hasClass('active')) {
			$field.removeClass('open');
			$fieldAction.removeClass('active');
		}
		else {
			$field.addClass('open');
			$fieldAction.addClass('active');
		}
		
	}
	
	/**
	 * Updates the hidden field with all the set up settings
	 */
	updateSettingsInput() {
	
		this.$settingsSection.find('.setting-row :input').each( (index: number, elem: Element) => {
			
			const $elem: JQuery = $(elem);
			
			if ( $elem.is(':checkbox') ) {
				this.field.settings[ $elem.attr('name') ] = $elem.is(':checked') ? 'yes' : 'no';
			}
			else {
				this.field.settings[ $elem.attr('name') ] = $elem.val();
			}
			
		});
		
		const $fieldSettingsButton: JQuery = this.$elem.find('i.field-settings'),
		      fieldSettings: FieldSettings = this.field.settings;
		
		if (fieldSettings.visibility === 'no' || fieldSettings.column_name !== '' || fieldSettings.prefix !== '' || fieldSettings.suffix !== '') {
			$fieldSettingsButton.addClass('with-settings');
		}
		else {
			$fieldSettingsButton.removeClass('with-settings');
		}
		
		this.$settingsInput.val( JSON.stringify(this.field.settings) );
		
	}
	
	/**
	 * Rearrange the position selector in the field's settings
	 */
	rearrangePositionSelect() {
		
		this.maybeAddDefaultSettings();
		
		const numFields: number        = this.$elem.parent().find('.selected-field').length,
		      fieldPosition: number    = parseInt( this.field.settings.position ),
		      $positionOptions: JQuery = this.$fieldPosition.find('option');
		
		if ($positionOptions.length !== numFields) {
			
			$positionOptions.remove();
			
			for (let i = 0; i < numFields; i++) {
				this.$fieldPosition.append(`<option value="${ i }"${ i === fieldPosition ? ' selected="selected"' : '' }>${ i }</option>`);
			}
			
		}
		else {
			$positionOptions.filter(':selected').removeAttr('selected');
			$positionOptions.eq(fieldPosition).attr('selected', 'selected');
		}
		
		// This triggers the "adjustFieldPosition" method to adjust the field position, if needed.
		this.adjustFieldPosition();
		this.updateSettingsInput();
		
	}
	
	/**
	 * Adjust the position of this field when chaging the position selector values
	 */
	adjustFieldPosition() {
		
		this.maybeAddDefaultSettings();
			
		const positionSelected: number = parseInt( this.field.settings.position ),
		      fieldIndex: number       = this.$elem.index('.selected-field');
		
		// Only change the field's position if is not the right one.
		if (positionSelected !== fieldIndex) {
			
			const $refElem: JQuery = this.globals.$selectedFieldsWrapper.find('.selected-field').eq(positionSelected);
			
			if (positionSelected < fieldIndex) {
				this.$elem.insertBefore( $refElem );
			}
			else {
				this.$elem.insertAfter( $refElem );
			}
			
		}
		
	}
	
	/**
	 * Add/Remove the visibility icon when necessary
	 *
	 * @param {boolean} isVisible
	 */
	maybeAddVisibilityIcon(isVisible) {
		
		const $fieldActions: JQuery = this.$elem.find('.selected-field--actions');
		
		if (!isVisible) {
			$fieldActions.prepend(`<i class="field-hidden atum-icon atmi-hidden atum-tooltip" title="${ this.settings.get('fieldNotVisible') }"></i>`);
			this.globals.tooltip.addTooltips($fieldActions);
		}
		else {
			$fieldActions.find('.field-hidden').remove();
		}
		
		this.globals.summary.maybeCreateSummary();
		
	}
	
	/**
	 * Add the default settings to the current field if needed.
	 * It's important that all the selected fields always have settings.
	 */
	maybeAddDefaultSettings() {
		
		if (typeof this.field.settings === 'undefined' || !this.field.settings) {
			
			const fieldSettings: FieldSettings = {
				column_name: '',
				position   : this.$elem.index('.selected-field'),
				prefix     : '',
				suffix     : '',
				visibility : 'yes',
			};
			
			this.field.settings = fieldSettings;
			
		}
		
	}
	
}