Vue.component( 'jet-engine-shortcode-generator', {
	name: 'jet-engine-shortcode-generator',
	template: '#jet-engine-shortcode-generator',
	data: function() {
		const {
			sources,
			object_fields: objectFields,
			source_args: sourceArgs,
			meta_fields: metaFields,
			options_pages: optionsPages,
			callbacks,
			cb_args: cbArgs,
			context_list: contextList,
			sanitize_values: sanitizeValues,
			labels,
			shortcode_types: shortcodeTypes,
			tag_type: tagType,
		} = window.JetEngineDashboardConfig.shortode_generator;

		return {
			sources,
			objectFields,
			sourceArgs,
			metaFields,
			optionsPages,
			callbacks,
			cbArgs,
			contextList,
			sanitizeValues,
			labels,
			shortcodeTypes,
			tagType,
			shortcode: '[jet_engine_data ]',
			controls: {},
			showCopyShortcode: undefined !== navigator.clipboard && undefined !== navigator.clipboard.writeText,
			attrs: {
				shortcode_types: 'jet_engine_data',
				tag_type: 'selfclosed',
			},
			copied: false,
		};
	},
	created: function() {

		const addControl = (name, config) => this.addControl(name, config);

		if ( 1 < this.shortcodeTypes.length ) {
			addControl( 'shortcode_types', {
				label: this.labels.shortcode_types.label,
				description: this.labels.shortcode_types.description,
				type: 'select',
				default: 'jet_engine_data',
				options: this.shortcodeTypes,
			} );
		}

		const conditionJetEngineData = {
			'shortcode_types': 'jet_engine_data',
		};

		addControl( 'dynamic_field_source', {
			label: this.labels.dynamic_field_source.label,
			type: 'select',
			default: 'object',
			options: this.sources,
			condition: conditionJetEngineData,
		} );

		addControl( 'sanitize', {
			label: this.labels.sanitize.label,
			type: 'select',
			default: this.getSanitizeDefault(),
			options: this.sanitizeValues,
			condition: conditionJetEngineData,
		} );

		addControl( 'dynamic_field_post_object', {
			label: this.labels.dynamic_field_post_object.label,
			type: 'select',
			default: 'post_title',
			groups: this.objectFields,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'object',
			},
		} );

		addControl( 'dynamic_field_wp_excerpt', {
			label: this.labels.dynamic_field_wp_excerpt.label,
			type: 'switcher',
			default: '',
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'object',
				'dynamic_field_post_object': 'post_excerpt',
			},
		} );

		addControl( 'dynamic_excerpt_more', {
			label: this.labels.dynamic_excerpt_more.label,
			type: 'text',
			default: '...',
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'object',
				'dynamic_field_post_object': 'post_excerpt',
			},
		} );

		addControl( 'dynamic_excerpt_length', {
			label: this.labels.dynamic_excerpt_length.label,
			type: 'text',
			default: 0,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'object',
				'dynamic_field_post_object': 'post_excerpt',
			},
		} );

		addControl( 'dynamic_field_post_meta', {
			label: this.labels.dynamic_field_post_meta.label,
			type: 'select',
			default: '',
			groups: this.metaFields,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'meta',
			},
		} );

		addControl( 'dynamic_field_option', {
			label: this.labels.dynamic_field_option.label,
			type: 'select',
			default: '',
			groups: this.optionsPages,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'options_page',
			},
		} );

		addControl( 'dynamic_field_var_name', {
			label: this.labels.dynamic_field_var_name.label,
			type: 'text',
			default: '',
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source': 'query_var',
			},
		} );

		if ( this.sourceArgs && this.sourceArgs.length ) {
			for (var i = 0; i < this.sourceArgs.length; i++) {
				addControl( this.sourceArgs[ i ].name, this.sourceArgs[ i ].data );
			}
		}

		addControl( 'dynamic_field_post_meta_custom', {
			label: this.labels.dynamic_field_post_meta_custom.label,
			type: 'text',
			default: '',
			description: this.labels.dynamic_field_post_meta_custom.description,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_source!': [ 'query_var', 'options_page', 'relations_hierarchy' ],
			},
		} );

		addControl( 'hide_if_empty', {
			label: this.labels.hide_if_empty.label,
			type: 'switcher',
			default: '',
			condition: conditionJetEngineData,
		} );

		addControl( 'field_fallback', {
			label: this.labels.field_fallback.label,
			type: 'text',
			default: '',
			condition: {
				...conditionJetEngineData,
				'hide_if_empty': false,
			},
		} );

		addControl( 'dynamic_field_filter', {
			label: this.labels.dynamic_field_filter.label,
			type: 'switcher',
			default: '',
			condition: conditionJetEngineData,
		} );

		const repeaterFields = {};

		repeaterFields.filter_callback = {
			label: this.labels.filter_callback.label,
			type: 'select',
			default: '',
			options: this.callbacks,
			condition: conditionJetEngineData,
		};

		for ( const [ fieldName, fieldData ] of Object.entries( this.cbArgs ) ) {
			repeaterFields[ fieldName ] = fieldData;
		}

		addControl( 'filter_callbacks', {
			label: 'Applied Callbacks',
			type: 'repeater',
			title: 'filter_callback',
			fields: repeaterFields,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_filter': 'yes',
			},
		} );

		this.$set( this.attrs, 'filter_callbacks', [] );

		addControl( 'dynamic_field_custom', {
			label: this.labels.dynamic_field_custom.label,
			type: 'switcher',
			default: '',
			condition: conditionJetEngineData,
		} );

		addControl( 'dynamic_field_format', {
			label: this.labels.dynamic_field_format.label,
			type: 'textarea',
			default: '%s',
			description: this.labels.dynamic_field_format.description,
			condition: {
				...conditionJetEngineData,
				'dynamic_field_custom': 'yes',
			},
		} );

		addControl( 'object_context', {
			label: this.labels.object_context.label,
			type: 'select',
			default: 'default_object',
			options: this.contextList,
			condition: conditionJetEngineData,
		} );

		addControl( 'tag_type', {
			label: this.labels.tag_type.label,
			description: this.labels.tag_type.description,
			type: 'select',
			default: 'selfclosed',
			options: this.tagType,
			condition: {
				'shortcode_types!': 'jet_engine_data',
			},
		} );

		window.JetPlugins.hooks.doAction( 'jetEngine.shortcodeGenerator.controls', addControl, this );
	},
	computed: {
		effectiveSanitizeDefault: function() {
			return this.getSanitizeDefault();
		},
		generatedShortcode: function() {

			let isEnclosing = false;
			let currentTag = this.attrs.shortcode_types || 'jet_engine_data';

			var result = '[' + currentTag;

			const attrsToParse = [];

			for ( const attr in this.attrs ) {

				if ( ! this.isVisible( this.controls[ attr ] ) ) {
					continue;
				}

				let value = this.attrs[ attr ];

				if ( 'shortcode_types' === attr ) {
					continue;
				}

				if ( 'tag_type' === attr ) {

					if ( 'enclosed' === value ) {
						isEnclosing = true;
					}

					continue;
				}

				if ( 'sanitize' === attr && value === this.effectiveSanitizeDefault ) {
					continue;
				}

				if ( 'sanitize' !== attr && value === this.controls[ attr ].default ) {
					continue;
				}

				if ( value instanceof Array ) {

					let toString = [];

					for ( var i = 0; i < value.length; i++ ) {

						if ( ! value[ i ]
							|| 'object' !== typeof value[ i ]
							|| Array.isArray( value[ i ] ) ) {
							toString.push( value[ i ] );

							if ( ! attrsToParse.includes( attr ) ) {
								attrsToParse.push( attr );
							}
							continue;
						}

						let row = { ...value[ i ] };

						if ( undefined !== row._id ) {
							delete row._id;
						}

						if ( undefined !== row.collapsed ) {
							delete row.collapsed;
						}

						for ( const prop in row ) {
							let field = this.controls[ attr ].fields[ prop ]
							if ( ! this.isRepeaterFieldVisible( field, row ) ) {
								delete row[ prop ];
							}
						}

						row = new URLSearchParams( row );
						toString.push( '{' + row.toString() + '}' );
					}

					value = toString.join( ',' );
				} else {
					value = JSON.stringify( value );
				}

				result += ' ' + attr + '=' + value;

			}

			if ( attrsToParse.length ) {
				result += ' _parse_attrs=' + attrsToParse.join( ',' );
			}

			result += ']';

			if ( isEnclosing ) {
				result += 'Add your content here...[/' + currentTag + ']';
			}

			return result;

		},
	},
	watch: {
		'attrs.dynamic_field_source': function( source, previousSource ) {
			const previousDefault = this.getSanitizeDefault( previousSource );

			if ( this.attrs.sanitize === previousDefault ) {
				this.$set( this.attrs, 'sanitize', this.getSanitizeDefault( source ) );
			}
		},
	},
	methods: {
		getSanitizeDefault: function( source ) {
			source = undefined === source ? this.attrs.dynamic_field_source : source;

			return 'options_page' === source ? 'wp_kses_post' : 'raw';
		},
		addControl: function( name, data ) {

			const preparedControls = this.getPreparedControls( { [name]: data } );

			for ( var i = 0; i < preparedControls.length; i++ ) {
				this.$set( this.controls, preparedControls[ i ].name, preparedControls[ i ] );
			}

		},
		addNewItem: function( event, props, parent, control, callback ) {

			props = props || [];

			var field = {};

			for ( const prop in control.fields ) {
				if ( control.fields[ prop ].default ) {
					field[ prop ] = control.fields[ prop ].default;
				}
			}

			field._id = Math.round( Math.random() * 1000000 );
			field.collapsed = false;

			parent.push( field );

			if ( callback && 'function' === typeof callback ) {
				callback( field, parent );
			}

		},
		deleteItemProp: function( id, key, parent ) {

			let index = this.searchByID( id, parent );

			if ( false === index ) {
				return;
			}

			let field = parent[ index ];

			delete field[ key ];

			parent.splice( index, 1, field );
		},
		setItemProp: function( id, key, value, parent ) {

			let index = this.searchByID( id, parent );

			if ( false === index ) {
				return;
			}

			let field = parent[ index ];

			field[ key ] = value;

			parent.splice( index, 1, field );

		},
		cloneItem: function( index, id, parent, callback ) {

			let field = JSON.parse( JSON.stringify( parent[ index ] ) );

			field.collapsed = false;
			field._id = Math.round( Math.random() * 1000000 );

			parent.splice( index + 1, 0, field );

			if ( callback && 'function' === typeof callback ) {
				callback( field, parent, id );
			}

		},
		deleteItem: function( index, id, parent, callback ) {

			index = this.searchByID( id, parent );

			if ( false === index ) {
				return;
			}

			parent.splice( index, 1 );

			if ( callback && 'function' === typeof callback ) {
				callback( id, index, parent );
			}

		},
		isCollapsed: function( parent ) {
			if ( undefined === parent.collapsed || true === parent.collapsed ) {
				return true;
			} else {
				return false;
			}
		},
		searchByID: function( id, list ) {

			for ( var i = 0; i < list.length; i++ ) {
				if ( id == list[ i ]._id ) {
					return i;
				}
			}

			return false;

		},
		getPreparedControls: function( inputControls ) {

			controls = [];

			for ( const controlID in inputControls ) {

				let control     = inputControls[ controlID ];
				let optionsList = [];
				let type        = control.type;
				let label       = control.label;
				let description = control.description || '';
				let defaultVal  = control.default;
				let groupsList  = [];
				let condition   = control.condition || {};
				let fields      = false;
				let title       = false;
				let multiple    = false;
				let inputType   = 'text';

				switch ( control.type ) {

					case 'text':
						type = 'cx-vui-input';
						break;

					case 'number':
						type = 'cx-vui-input';
						inputType = 'number';
						break;

					case 'textarea':
						type = 'cx-vui-textarea';
						break;

					case 'switcher':
						type = 'cx-vui-switcher';
						if ( 'yes' === defaultVal || 'true' === defaultVal ) {
							defaultVal = true;
						} else {
							defaultVal = false;
						}
						break;

					case 'repeater':
						type = 'repeater';
						title = control.title;
						fields = control.fields;
						break;

					case 'select':
						type = 'cx-vui-select';

						if ( control.groups ) {
							groupsList = this.prepareGroupsList(control.groups);
						} else {
							optionsList = this.prepareOptionsList(control.options);
						}

						break;

					case 'select2':
						type = 'cx-vui-f-select';
						multiple = control.multiple;
						optionsList = this.prepareOptionsList(control.options);

						break;

				}

				if ( undefined === this.attrs[ controlID ] ) {
					this.$set( this.attrs, controlID, defaultVal );
				}

				controls.push( {
					type,
					name: controlID,
					label,
					description,
					default: defaultVal,
					optionsList,
					multiple,
					groupsList,
					condition,
					fields,
					title: control.title,
					inputType,
				} );

			}

			return controls;

		},
		prepareGroupsList: function(groups) {
			const groupsList = [];

			for ( var i = 0; i < groups.length; i++) {
				let group = groups[ i ];
				let groupOptions = [];

				if ( group.options ) {
					groupOptions = this.prepareOptionsList(group.options);
				} else if ( group.values ) {
					for ( var j = 0; j < group.values.length; j++ ) {
						groupOptions.push( group.values[ j ] );
					}
				}

				groupsList.push( {
					label: group.label,
					options: groupOptions,
				} );
			}

			return groupsList;
		},
		prepareOptionsList: function(options) {
			const optionsList = [];

			for ( const optionValue in options ) {
				if ( options[optionValue] && options[optionValue].value !== undefined ) {
					optionsList.push( {
						value: options[ optionValue ].value,
						label: options[ optionValue ].label,
					} );
				} else {
					optionsList.push( {
						value: optionValue,
						label: options[ optionValue ],
					} );
				}
			}

			return optionsList;
		},
		copyShortcodeToClipboard: function() {

			var self = this;

			navigator.clipboard.writeText( this.generatedShortcode ).then( function() {
				// clipboard successfully set
				self.copied = true;
				setTimeout( function() {
					self.copied = false;
				}, 2000 );
			}, function() {
				// clipboard write failed
			} );
		},
		isVisible: function( control ) {
			if ( ! control ) {
				return false;
			}
			if ( ! control.condition ) {
				return true;
			} else {
				return this.checkCondition( control.condition, this.attrs );
			}
		},
		isRepeaterFieldVisible: function( control, item ) {

			let res = false;

			if ( ! control ) {
				return false;
			}

			if ( ! control.condition ) {
				res = true;
			} else {
				res = this.checkCondition( control.condition, item );
			}

			return res;

		},
		checkCondition: function( condition, attrs ) {

			let checkResult = true;

			condition = condition || {};

			for ( const [ fieldName, check ] of Object.entries( condition ) ) {

				let isExcl = fieldName.includes( '!' );
				let valToCheck = check;

				if ( 'yes' === check ) {
					valToCheck = true;
				}

				if ( 'no' === check ) {
					valToCheck = false;
				}

				if ( isExcl ) {

					let rFieldName = fieldName.replace( '!', '' );

					if ( valToCheck && valToCheck.length && 'string' !== typeof valToCheck ) {
						if ( valToCheck.includes( attrs[ rFieldName ] ) || valToCheck.includes( this.attrs[ rFieldName ] ) ) {
							checkResult = false;
						}
					} else {
						if ( valToCheck == attrs[ rFieldName ] || valToCheck == this.attrs[ rFieldName ] ) {
							checkResult = false;
						}
					}

				} else {
					if ( valToCheck && valToCheck.length && 'string' !== typeof valToCheck ) {
						if ( ! valToCheck.includes( attrs[ fieldName ] ) && ! valToCheck.includes( this.attrs[ fieldName ] ) ) {
							checkResult = false;
						}
					} else {
						if ( valToCheck != attrs[ fieldName ] && valToCheck != this.attrs[ fieldName ] ) {
							checkResult = false;
						}
					}
				}

			}

			return checkResult;

		}
	},
} );
