( function ( $, data, wp, _ ) {
	$( function () {
		const $table = $( '.wdevs-coe-template-columns' ),
			$tbody = $( '.wdevs-coe-template-columns-rows' ),
			$save_button = $( '.wdevs-coe-template-columns-save' ),
			$row_template = wp.template( 'wdevs-coe-template-columns-row' ),
			$blank_template = wp.template(
				'wdevs-coe-template-columns-row-blank'
			),
			$configure_button = $(
				'.wdevs-coe-template-configure-column-button'
			);

		// Backbone model
		const Column = Backbone.Model.extend( {
			changes: {},
			logChanges( changedRows ) {
				const changes = this.changes || {};

				_.each( changedRows.columns, function ( row, id ) {
					changes.columns = changes.columns || { columns: {} };
					changes.columns[ id ] = _.extend(
						changes.columns[ id ] || { column_id: id },
						row
					);
				} );

				if ( typeof changedRows.name !== 'undefined' ) {
					changes.name = changedRows.name;
				}

				this.changes = changes;
				this.trigger( 'change:columns' );
			},
			save() {
				$.post(
					window.wdceoData.ajaxUrl,
					{
						action: window.wdceoData.templateColumnsAction,
						nonce: window.wdceoData.nonce,
						changes: this.changes,
						id: data.id,
					},
					this.onSaveResponse,
					'json'
				);
			},
			onSaveResponse( response, textStatus ) {
				if ( 'success' === textStatus ) {
					if ( response.success ) {
						if ( response.data.id !== data.id ) {
							data.id = response.data.id;
							if ( window.history.pushState ) {
								window.history.pushState(
									{},
									'',
									'admin.php?page=wc-settings&tab=wdevs_coe&section=templates&template_id=' +
										response.data.id
								);
							}
						}
						column.set(
							'selectableColumns',
							response.data.selectableColumns
						);
						column.set(
							'columnsFlattened',
							response.data.columnsFlattened
						);
						column.trigger( 'change:columns' );
						column.changes = {};
						column.trigger( 'saved:columns' );
						window.onbeforeunload = null;
					} else {
						window.alert( data.strings.save_failed );
					}
				}
			},
		} );

		// Backbone view
		const ColumnView = Backbone.View.extend( {
			rowTemplate: $row_template,
			initialize() {
				this.listenTo(
					this.model,
					'change:columns',
					this.setUnloadConfirmation
				);
				this.listenTo(
					this.model,
					'saved:columns',
					this.clearUnloadConfirmation
				);
				this.listenTo( this.model, 'saved:columns', this.render );
				this.listenTo( this.model, 'rerender', this.render );
				$tbody.on(
					'sortupdate',
					{ view: this },
					this.updateModelOnSort
				);
				$( window ).on(
					'beforeunload',
					{ view: this },
					this.unloadConfirmation
				);
				$save_button.on( 'click', { view: this }, this.onSubmit );

				$( document.body ).on(
					'input change',
					'#name',
					{ view: this },
					this.onUpdateTemplate
				);

				$( document.body ).on(
					'click',
					'.wdevs-coe-template-configure-column-button',
					{ view: this },
					this.onAddColumn
				);
				$( document.body ).on(
					'wc_backbone_modal_response',
					_.bind( this.onConfigureColumnSubmitted, this )
				);
				$( document.body ).on(
					'wc_backbone_modal_validation',
					{ view: this },
					this.validateFormArguments
				);
				$( document.body ).on(
					'wc_backbone_modal_loaded',
					{ view: this },
					this.onModalLoaded
				);
				$( document.body ).on(
					'change',
					'.wc-backbone-modal-content select[name="category_id"]',
					{ view: this },
					this.onCategoryChange
				);
				$( document.body ).on(
					'change',
					'.wc-backbone-modal-content select[name="field_id"]',
					{ view: this },
					this.onFieldChange
				);
			},
			onUpdateTemplate( event ) {
				const view = event.data.view,
					model = view.model,
					value = $( this ).val(),
					$target = $( event.target ),
					attribute = $target.data( 'attribute' ),
					changes = {};

				event.preventDefault();
				changes[ attribute ] = value;
				model.set( attribute, value );
				model.logChanges( changes );
				view.render();
			},
			block() {
				$( this.el ).block( {
					message: null,
					overlayCSS: {
						background: '#fff',
						opacity: 0.6,
					},
				} );
			},
			unblock() {
				$( this.el ).unblock();
			},
			render() {
				const columns = this.model.get( 'columnsFlattened' );
				const view = this;

				this.$el.empty();
				this.unblock();

				if ( _.size( columns ) ) {
					const columnsArray = Object.entries( columns );

					const sortedColumns = _.sortBy(
						columnsArray,
						( [ , rowData ] ) => parseInt( rowData.order, 10 )
					);

					sortedColumns.forEach( ( [ key, rowData ] ) => {
						rowData.column_id = key;

						view.$el.append( view.rowTemplate( rowData ) );
						const $tr = view.$el.find( `tr[data-id="${ key }"]` );

						$tr.find(
							'.wc-shipping-zone-method-title > a'
						).replaceWith(
							'<span>' +
								$tr
									.find(
										'.wc-shipping-zone-method-title > a'
									)
									.text() +
								'</span>'
						);
						const $del = $tr.find(
							'.wc-shipping-zone-method-delete'
						);
						$tr.find(
							'.wc-shipping-zone-method-title .row-actions'
						)
							.empty()
							.html( $del );
					} );
					this.$el
						.find( '.wdevs-ceo-column-edit' )
						.on( 'click', { view: this }, this.onConfigureColumn );
					this.$el
						.find( '.wdevs-ceo-column-delete' )
						.on( 'click', { view: this }, this.onDeleteRow );
				} else {
					view.$el.append( $blank_template );
				}
			},
			onSubmit( event ) {
				$save_button.addClass( 'is-busy' );
				event.data.view.block();
				event.data.view.model.save();
				event.preventDefault();
			},
			onDeleteRow( event ) {
				const column_id = $( this ).closest( 'tr' ).data( 'id' );

				event.preventDefault();

				if (
					window.confirm( data.strings.delete_column_confirmation )
				) {
					const model = event.data.view.model,
						columnsFlattened = model.get( 'columnsFlattened' ),
						column = columnsFlattened[ column_id ];
					const changes = {};

					if ( column ) {
						const column_data = {
							category_id: column.category_id,
							deleted: 'deleted',
						};

						changes.columns = {};
						changes.columns[ column_id ] = column_data;

						columnView.block();
						$configure_button.prop( 'disabled', true );
						$configure_button.addClass( 'is-busy' );

						model.logChanges( changes );

						model.save();
					}
				}
			},
			setUnloadConfirmation() {
				this.needsUnloadConfirm = true;
				$save_button.prop( 'disabled', false );
				$save_button.removeClass( 'is-busy' );
			},
			clearUnloadConfirmation() {
				this.needsUnloadConfirm = false;
				$save_button.attr( 'disabled', 'disabled' );

				$configure_button.prop( 'disabled', false );
				$configure_button.removeClass( 'is-busy' );
			},
			unloadConfirmation( event ) {
				if ( event.data.view.needsUnloadConfirm ) {
					event.returnValue = data.strings.unload_confirmation_msg;
					window.event.returnValue =
						data.strings.unload_confirmation_msg;
					return data.strings.unload_confirmation_msg;
				}
			},
			updateModelOnSort( event ) {
				const view = event.data.view,
					model = view.model,
					columns = model.get( 'columnsFlattened' ),
					changes = {
						columns: {},
					};

				_.each( columns, function ( column, column_id ) {
					const old_position = parseInt( column.order, 10 );

					const new_position = parseInt(
						$table
							.find( 'tr[data-id="' + column_id + '"]' )
							.index() + 1,
						10
					);

					if ( old_position !== new_position ) {
						//columns[column_id].order = new_position;
						// changes.columns = changes.columns || {columns: {}};
						changes.columns[ column_id ] = {
							order: new_position,
							category_id: column.category_id,
						};
					}
				} );

				if ( _.size( changes ) ) {
					view.block();
					$configure_button.prop( 'disabled', true );
					$configure_button.addClass( 'is-busy' );

					model.logChanges( changes );

					model.save();
				}
			},
			onConfigureColumn( event ) {
				const column_id = $( this ).closest( 'tr' ).data( 'id' );

				event.preventDefault();
				$( this ).WCBackboneModal( {
					template: 'wdevs-coe-template-configure-column',
					variable: {
						template_id: data.id,
						column_id,
						action: 'edit',
					},
				} );
			},
			onConfigureColumnSubmitted( event, target, posted_data ) {
				if ( 'wdevs-coe-template-configure-column' === target ) {
					const view = this,
						model = view.model,
						// columns = _.clone(model.get('columnsFlattened')) || {},
						changes = {};

					const modalContent = $( '.wc-backbone-modal-content' );

					//When editing; select is disabled, and value is not passed in formData
					if ( ! posted_data.category_id ) {
						const $categorySelect = modalContent.find(
							'select[name="category_id"]'
						);
						if ( $categorySelect.length ) {
							posted_data.category_id = $categorySelect.val();
						}
					}

					//When editing; select is disabled, and value is not passed in formData
					if ( ! posted_data.field_id ) {
						const $fieldSelect = modalContent.find(
							'select[name="field_id"]'
						);
						if ( $fieldSelect.length ) {
							posted_data.field_id = $fieldSelect.val();
						}
					}

					const column_id =
						posted_data.column_id || posted_data.field_id;

					const column_data = {
						category_id: posted_data.category_id,
						name: posted_data.name,
					};

					// columns[column_id] = column_data;

					changes.columns = {};
					changes.columns[ column_id ] = column_data;

					view.block();
					$configure_button.prop( 'disabled', true );
					$configure_button.addClass( 'is-busy' );

					model.logChanges( changes );

					model.save();
				}
			},
			onAddColumn( event ) {
				event.preventDefault();
				$( this ).WCBackboneModal( {
					template: 'wdevs-coe-template-configure-column',
					variable: {
						template_id: data.id,
						action: 'create',
						column_id: null,
					},
				} );
			},
			onModalLoaded( event, target ) {
				if ( target === 'wdevs-coe-template-configure-column' ) {
					const modalContent = $( '.wc-backbone-modal-content' );

					const $categorySelect = modalContent.find(
						'select[name="category_id"]'
					);
					const $emptyCategoryOption = $categorySelect
						.find( 'option[value=""]' )
						.clone();
					$categorySelect.empty().append( $emptyCategoryOption );

					let newColumn = true;

					const modalData = modalContent.data();
					if ( modalData && modalData.column_id ) {
						const model = event.data.view.model,
							columnsFlattened = model.get( 'columnsFlattened' ),
							column = columnsFlattened[ modalData.column_id ];
						if ( column ) {
							newColumn = false;
							if (
								data.selectableColumns &&
								data.selectableColumns[ column.category_id ]
							) {
								if (
									data.selectableColumns[ column.category_id ]
										.fields &&
									data.selectableColumns[ column.category_id ]
										.fields[ modalData.column_id ]
								) {
									const categoryOption = {
										value: column.category_id,
										text: data.selectableColumns[
											column.category_id
										].name,
										selected: true,
									};

									const fieldOption = {
										value: modalData.column_id,
										text: data.selectableColumns[
											column.category_id
										].fields[ modalData.column_id ].name,
										selected: true,
									};

									if ( $categorySelect ) {
										$categorySelect.empty();
										$categorySelect.append(
											$( '<option>', categoryOption )
										);
										$categorySelect.trigger( 'input' );
										$categorySelect.prop(
											'disabled',
											true
										);
									}

									const $fieldSelect = modalContent.find(
										'select[name="field_id"]'
									);

									if ( $fieldSelect ) {
										$fieldSelect.empty();
										$fieldSelect.append(
											$( '<option>', fieldOption )
										);
										$fieldSelect.trigger( 'input' );
										$fieldSelect.prop( 'disabled', true );
									}

									const rowData = {
										template_id: data.id,
										category_id: column.category_id,
										field_id: modalData.column_id,
										name: column.name,
									};

									$( '.wc-backbone-modal-content' )
										.find( 'input' )
										.each( function () {
											const attribute =
												$( this ).data( 'attribute' );
											if ( attribute ) {
												$( this ).val(
													rowData[ attribute ]
												);
												$( this ).trigger( 'input' );
											}
										} );
								}
							}
						}
					}

					if ( newColumn && data.selectableColumns ) {
						for ( const [
							categoryKey,
							categoryData,
						] of Object.entries( data.selectableColumns ) ) {
							if ( categoryData.fields ) {
								const hasSelectableField = Object.values(
									categoryData.fields
								).some(
									( field ) => field.selectable === true
								);

								if ( hasSelectableField ) {
									$categorySelect.append(
										$( '<option>', {
											value: categoryKey,
											text: categoryData.name,
										} )
									);
								}
							}
						}
						$categorySelect.val( '' ).trigger( 'change' );
					}
				}
			},
			onCategoryChange() {
				const modalContent = $( '.wc-backbone-modal-content' );

				const $fieldSelect = modalContent.find(
					'select[name="field_id"]'
				);
				const $fieldContainer = modalContent.find(
					'.wdevs-coe-column-field'
				);
				const category_id = $( this ).val();

				$fieldContainer.hide();

				if ( category_id ) {
					if (
						data.selectableColumns &&
						data.selectableColumns[ category_id ] &&
						data.selectableColumns[ category_id ].fields
					) {
						const $emptyOption = $fieldSelect
							.find( 'option[value=""]' )
							.clone();
						$fieldSelect.empty().append( $emptyOption );

						Object.entries(
							data.selectableColumns[ category_id ].fields
						).forEach( ( [ fieldKey, fieldData ] ) => {
							if ( fieldData.selectable !== false ) {
								$fieldSelect.append(
									$( '<option>', {
										value: fieldKey,
										text: fieldData.field || fieldKey,
									} )
								);
							}
						} );

						$fieldContainer.show();
					}
				}

				$fieldSelect.val( '' ).trigger( 'change' );
			},
			onFieldChange() {
				const modalContent = $( '.wc-backbone-modal-content' );
				const $nameInput = modalContent.find( 'input[name="name"]' );
				const $nameContainer = modalContent.find(
					'.wdevs-coe-column-name'
				);
				const $helpText = modalContent.find( '#field-help-text' );
				const selectedValue = $( this ).val();

				$nameContainer.hide();
				$nameInput.val( '' );

				if ( selectedValue ) {
					const $categorySelect = modalContent.find(
						'select[name="category_id"]'
					);
					if ( $categorySelect.length ) {
						const selectedCategoryId = $categorySelect.val();
						if (
							data.selectableColumns &&
							data.selectableColumns[ selectedCategoryId ] &&
							data.selectableColumns[ selectedCategoryId ].fields
						) {
							for ( const [
								fieldId,
								fieldProperties,
							] of Object.entries(
								data.selectableColumns[ selectedCategoryId ]
									.fields
							) ) {
								if ( fieldId === selectedValue ) {
									$nameInput.val( fieldProperties.name );
									if ( fieldProperties.description ) {
										$helpText.html(
											fieldProperties.description
										);
									}
									break;
								}
							}
						}
					}

					$nameContainer.show();
				}

				$nameInput.trigger( 'input' );
			},
			validateFormArguments( event, target, formData ) {
				if ( target === 'wdevs-coe-template-configure-column' ) {
					const nextButton = document.getElementById( 'btn-ok' );
					nextButton.disabled = true;
					nextButton.classList.add( 'disabled' );

					const modalContent = $( '.wc-backbone-modal-content' );

					//When editing; select is disabled, and value is not passed in formData
					if ( ! formData.category_id ) {
						const $categorySelect = modalContent.find(
							'select[name="category_id"]'
						);
						if ( $categorySelect.length ) {
							formData.category_id = $categorySelect.val();
						}
					}

					//When editing; select is disabled, and value is not passed in formData
					if ( ! formData.field_id ) {
						const $fieldSelect = modalContent.find(
							'select[name="field_id"]'
						);
						if ( $fieldSelect.length ) {
							formData.field_id = $fieldSelect.val();
						}
					}

					if (
						formData.category_id &&
						formData.field_id &&
						formData.name
					) {
						nextButton.disabled = false;
						nextButton.classList.remove( 'disabled' );
					}
				}
			},
		} );

		const column = new Column( {
			columnsFlattened: data.columnsFlattened,
			name: data.name,
		} );
		const columnView = new ColumnView( {
			model: column,
			el: $tbody,
		} );

		if ( $table.length ) {
			columnView.render();
			$tbody.sortable( {
				items: 'tr',
				cursor: 'move',
				axis: 'y',
				handle: 'td.wc-shipping-zone-method-sort',
				scrollSensitivity: 40,
			} );
		}

		$( '.wdevs-coe-template-delete' ).each( function () {
			$( this ).on( 'click', function ( event ) {
				event.preventDefault();

				const templateId = $( this ).closest( 'tr' ).data( 'id' );

				if (
					templateId &&
					window.confirm(
						window.wdceoData.strings.delete_template_confirmation
					)
				) {
					$.post(
						window.wdceoData.ajaxUrl,
						{
							action: window.wdceoData.templateDeleteAction,
							nonce: window.wdceoData.nonce,
							id: templateId,
						},
						function ( response ) {
							if ( response.success ) {
								window.location.reload();
							} else if ( response.data.message ) {
								window.alert( response.data.message );
							}
						},
						'json'
					);
				}
			} );
		} );
	} );
} )( jQuery, wdceoData, wp, _ );
