/**
 * UpSolution Element: List Filter
 */
! function( $, _undefined ) {
	"use strict";

	const abs = Math.abs;
	const max = Math.max;
	const min = Math.min;
	const urlManager = $ush.urlManager();
	const PREFIX_FOR_URL_PARAM = '_';
	const RANGE_VALUES_BY_DEFAULT = [ 0, 1000 ];
	const DELETE_FILTER = null;

	let lastResult;

	/**
	 * @param {String} values The values.
	 * @return {[]} Returns an array of range values.
	 */
	function parseValues( values ) {
		values = $ush.toString( values );
		if ( ! values || ! values.includes( '-' ) ) {
			return RANGE_VALUES_BY_DEFAULT;
		}
		return values.split( '-' ).map( $ush.parseFloat );
	}

	/**
	 * @param {Node} container.
	 */
	function usListFilter( container ) {
		const self = this;

		// Private "Variables"
		self.settings = {
			mobileWidth: 600,
		};
		self.$filters = {};
		self.result = {};

		// Bondable events.
		self._events = {
			filterСhanged: self.filterСhanged.bind( self ),
			searchValues: self.searchValues.bind( self ),
			resetFilter: self.resetFilter.bind( self ),
			resultСhanged: $ush.debounce( self.resultСhanged.bind( self ), 1 ),
			openSection: self.openSection.bind( self ),
			openMobileFilters: self.openMobileFilters.bind( self ),
			closeMobileFilters: self.closeMobileFilters.bind( self ),
			resize: $ush.debounce( self.resize.bind( self ), 10 ),
		};

		// Elements
		self.$container = $( container );
		self.$pageContent = $( 'main#page-content' );

		// Gets element settings
		if ( self.$container.is( '[onclick]' ) ) {
			$.extend( self.settings, self.$container[0].onclick() || {} );
		}

		// Init DatePicker https://api.jqueryui.com/datepicker/
		$( '.type_date_picker', container ).each( ( _, filter ) => {
			let $start = $( 'input:eq(0)', filter ),
				$end = $( 'input:eq(1)', filter ),
				$startContainer = $start.parent(),
				$endContainer = $start.parent(),
				startOptions = {},
				endOptions = {};

			if ( $startContainer.is( '[onclick]' ) ) {
				startOptions = $startContainer[0].onclick() || {};
			}
			if ( $endContainer.is( '[onclick]' ) ) {
				endOptions = $endContainer[0].onclick() || {};
			}

			$start.datepicker( $.extend( true, {
				isRTL: $ush.isRtl(),
				dateFormat: $start.data( 'date-format' ),
				beforeShow: ( _, inst ) => {
					inst.dpDiv.addClass( 'for_list_filter' );
				},
				onSelect: () => {
					$start.trigger( 'change' );
				},
				onClose: ( _, inst ) => {
					$end.datepicker( 'option', 'minDate', inst.input.datepicker( 'getDate' ) || null );
				},
			}, startOptions ) );

			$end.datepicker( $.extend( true, {
				isRTL: $ush.isRtl(),
				dateFormat: $end.data( 'date-format' ),
				beforeShow: ( _, inst ) => {
					inst.dpDiv.addClass( 'for_list_filter' );
				},
				onSelect: () => {
					$start.trigger( 'change' );
				},
				onClose: ( _, inst ) => {
					$start.datepicker( 'option', 'maxDate', inst.input.datepicker( 'getDate' ) || null );
				},
			}, endOptions ) );
		} );

		// Init Range Slider https://api.jqueryui.com/slider/
		$( '.type_range_slider', container ).each( ( _, filter ) => {
			function showFormattedResult( _, ui ) {
				$( '.for_min_value, .for_max_value', filter ).each( ( i, node ) => {
					let value = $ush.toString( ui.values[ i ] );
					if ( options.numberFormat ) {
						var numberFormat = $ush.toPlainObject( options.numberFormat ),
							decimals = $ush.parseInt( abs( numberFormat.decimals ) );
						if ( decimals ) {
							value = $ush.toString( $ush.parseFloat( value ).toFixed( decimals ) )
								.replace( /^(\d+)(\.)(\d+)$/, '$1' + numberFormat.decimal_separator + '$3' );
						}
						value = value.replace( /\B(?=(\d{3})+(?!\d))/g, numberFormat.thousand_separator );
					}
					$( node ).html( $ush.toString( options.unitFormat ).replace( '%d', value ) );
				} );
			}

			let $slider = $( '.ui-slider', filter );
			let options = {
				slider: {
					animate: true,
					min: RANGE_VALUES_BY_DEFAULT[0],
					max: RANGE_VALUES_BY_DEFAULT[1],
					range: true,
					step: 10,
					values: RANGE_VALUES_BY_DEFAULT,
					slide: showFormattedResult,
					change: showFormattedResult,
					stop: $ush.debounce( ( _, ui ) => {
						$( 'input[type=hidden]', filter )
							.val( ui.values.join( '-' ) )
							.trigger( 'change' );
					} ),
				},
				unitFormat: '%d', // example: $0 000.00
				numberFormat: null, // example: 0 000.00
			};
			if ( $slider.is( '[onclick]' ) ) {
				options = $.extend( true, options, $slider[0].onclick() || {} );
			}
			$slider.removeAttr( 'onclick' ).slider( options.slider );
		} );

		// Setup the UI
		if ( self.changeURLParams() ) {
			$( '[data-name]', self.container ).each( ( _, filter ) => {
				let $filter = $( filter ),
					name = $filter.data( 'name' ),
					compare = $ush.toString( $filter.data( 'value-compare' ) );
				if ( compare ) {
					compare = `|${compare}`;
				}
				self.$filters[ name + compare ] = $filter;
			});
			self.setupFields();
			urlManager.on( 'popstate', ( e ) => {
				self.setupFields();
				self.resultСhanged();
			} );
		}

		// Events
		$( '.w-filter-item', container )
			.on( 'change', 'input:not([name=search_values]), select', self._events.filterСhanged )
			.on( 'input change', 'input[name=search_values]', self._events.searchValues )
			.on( 'click', '.w-filter-item-reset', self._events.resetFilter )
			.on( 'click', '.w-filter-item-title', self._events.openSection );
		self.$container
			.on( 'click', '.w-filter-opener', self._events.openMobileFilters )
			.on( 'click', '.w-filter-list-closer, .w-filter-button-submit', self._events.closeMobileFilters );
		$us.$window
			.on( 'resize load', self._events.resize )

		self.on( 'resultСhanged', self._events.resultСhanged );
	}

	// List Filter API
	$.extend( usListFilter.prototype, $ush.mixinEvents, {

		/**
		 * Determines if enabled URL.
		 *
		 * @return {Boolean} True if enabled url, False otherwise.
		 */
		changeURLParams: function() {
			return this.$container.hasClass( 'change_url_params' );
		},

		/**
		 * Setup fields.
		 */
		setupFields: function() {
			const self = this;
			$.each( self.$filters, ( name, $filter ) => {
				self.resetFields( $filter );

				name = PREFIX_FOR_URL_PARAM + name;
				if ( ! urlManager.has( name ) ) {
					delete self.result[ name ];
					return;
				}

				let values = $ush.toString( urlManager.get( name ) );
				values.split( ',' ).map( ( value, i ) => {
					if ( $filter.hasClass( 'type_dropdown' ) ) {
						$( `select`, $filter ).val( value );

					} else if ( $filter.hasClass( 'type_date_picker' ) ) {
						let $input = $( `input:eq(${i})`, $filter );
						if ( $input.length && /\d{4}-\d{2}-\d{2}/.test( value ) ) {
							$input.val( $.datepicker.formatDate( $input.data( 'date-format' ), $.datepicker.parseDate( 'yy-mm-dd', value ) ) );
						}

					} else if ( $filter.hasClass( 'type_range_input' ) ) {
						if ( /([\.?\d]+)-([\.?\d]+)/.test( value ) ) {
							$( 'input', $filter ).each( ( i, input ) => { input.value = parseValues( value )[ i ] } );
						}

					} else if ( $filter.hasClass( 'type_range_slider' ) ) {
						if ( /([\.?\d]+)-([\.?\d]+)/.test( value ) ) {
							$( '.ui-slider', $filter ).slider( 'values', parseValues( value ) );
							$( `input[type=hidden]`, $filter ).val( value );
						}

						// For type_checkbox and type_radio
					} else {
						$( `input[value="${value}"]`, $filter ).prop( 'checked', true );
					}
				} );

				self.result[ name ] = values;

				$filter.addClass( 'has_value open' );
			} );
		},

		/**
		 * Search field to narrow choices.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		searchValues: function( e ) {

			const $filter = $( e.delegateTarget );
			const $items = $( '[data-value]', $filter );
			const value = $ush.toLowerCase( e.target.value ).trim();

			$items
				.filter( ( _, node ) => { return ! $( 'input', node ).is(':checked') } )
				.toggleClass( 'hidden', !! value );

			if ( $filter.hasClass( 'type_radio' ) ) {
				const $buttonAnyValue = $( '[data-value="*"]:first', $filter );
				if ( ! $( 'input', $buttonAnyValue ).is(':checked') ) {
					$buttonAnyValue
						.toggleClass( 'hidden', ! $ush.toLowerCase( $buttonAnyValue.text() ).includes( value ) );
				}
			}

			if ( value ) {
				$items
					.filter( ( _, node ) => { return $ush.toLowerCase( $( node ).text() ).includes( value ) } )
					.removeClass( 'hidden' )
					.length;
			}

			$( '.w-filter-item-message', $filter ).toggleClass( 'hidden', $items.is( ':visible' ) );
		},

		/**
		 * Generates a result from filters.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		filterСhanged: function( e ) {
			const self = this;

			let $filter = $( e.delegateTarget ),
				name = PREFIX_FOR_URL_PARAM + $ush.toString( $filter.data( 'name' ) ),
				compare = $filter.data( 'value-compare' ),
				value = e.target.value;

			if ( compare ) {
				name += `|${compare}`;
			}

			// TYPE: Checkboxes
			if ( $filter.hasClass( 'type_checkbox' ) ) {
				let values = [];
				$( 'input:checked', $filter ).each( ( _, input ) => {
					values.push( input.value );
				});

				if ( ! values.length ) {
					self.result[ name ] = DELETE_FILTER;
				} else {
					self.result[ name ] = values.toString();
				}

				// TYPE: Date Picker
			} else if ( $filter.hasClass( 'type_date_picker' ) ) {
				let values = [];
				$( 'input.hasDatepicker', $filter ).each( ( _, input ) => {
					let dateValue = $.datepicker.formatDate( 'yy-mm-dd', $( input ).datepicker( 'getDate' ) );
					if ( dateValue ) {
						values.push( dateValue );
					}
				} );

				if ( ! values.length ) {
					self.result[ name ] = DELETE_FILTER;
				} else {
					self.result[ name ] = values.toString();
				}

				// TYPE: Range input
			} else if ( $filter.hasClass( 'type_range_input' ) ) {
				let defaultValues = [], values = [];
				$( 'input', $filter ).each( ( i, input ) => {
					defaultValues[ i ] = input.dataset.value;
					values[ i ] = input.value || defaultValues[ i ];
				} );
				if ( ! values.length || values.toString() === defaultValues.toString() ) {
					self.result[ name ] = DELETE_FILTER;
				} else {
					self.result[ name ] = values.join( '-' );
				}

				// TYPE: Radio buttons and Dropdown
			} else {
				if ( $ush.rawurldecode( value ) === '*' ) {
					self.result[ name ] = DELETE_FILTER;
				} else {
					self.result[ name ] = value;
				}
			}

			self.trigger( 'resultСhanged' );

			$filter.toggleClass( 'has_value open', !! self.result[ name ] );
		},

		/**
		 * Sends result to the first Post/Product List.
		 *
		 * @event handler
		 */
		resultСhanged: function() {
			const self = this;
			if (
				! $ush.isUndefined( lastResult )
				&& $ush.comparePlainObject( self.result, lastResult )
			) {
				return;
			}
			lastResult = $ush.clone( self.result );

			if ( self.changeURLParams() ) {
				urlManager.set( self.result );
				urlManager.push( {} );
			}

			let $firstList = $( `
				.w-grid.us_post_list:visible,
				.w-grid.us_product_list:visible,
				.w-grid-none:visible
			`, self.$pageContent ).first();

			if ( $firstList.hasClass( 'w-grid-none' ) ) {
				$firstList = $firstList.prev();
			}

			$firstList.trigger( 'usListFilter', self.result );
		},

		/**
		 * Reset filter values.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		resetFilter: function( e ) {
			const self = this;

			e.stopPropagation();
			e.preventDefault();

			let $filter = $( e.delegateTarget ),
				name = PREFIX_FOR_URL_PARAM + $filter.data( 'name' ),
				compare = $filter.data( 'value-compare' );

			if ( compare ) {
				name += `|${compare}`;
			}
			self.result[ name ] = DELETE_FILTER;

			self.trigger( 'resultСhanged' );
			self.resetFields( $filter );
		},

		/**
		 * Reset filter fields.
		 *
		 * @param {Node} $filter
		 */
		resetFields: function( $filter ) {
			if ( $filter.hasClass( 'type_checkbox' ) ) {
				$( 'input[type=checkbox]', $filter ).prop( 'checked', false );

			} else if ( $filter.hasClass( 'type_radio' ) ) {
				$( 'input[type=radio]:first', $filter ).prop( 'checked', true );

			} else if ( $filter.hasClass( 'type_dropdown' ) ) {
				$( 'select', $filter ).prop( 'selectedIndex', 0 );

			} else if (
				$filter.hasClass( 'type_date_picker' )
				|| $filter.hasClass( 'type_range_input' )
			) {
				$( 'input', $filter ).val( '' );

			} else if ( $filter.hasClass( 'type_range_slider' ) ) {
				let $input = $( 'input[type=hidden]', $filter ),
					values = [
						$input.attr( 'min' ),
						$input.attr( 'max' )
					];
				$( '.ui-slider', $filter ).slider( 'values', values.map( $ush.parseFloat ) );
			}
			$filter.removeClass( 'has_value' );

			$( 'input[name="search_values"]', $filter ).val( '' );
			$( '.w-filter-item-value', $filter ).removeClass( 'hidden' );
		},

		/**
		 * Opens a section.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		openSection: function( e ) {
			if ( this.$container.hasClass( 'togglable' ) ) {
				let $filter = $( e.delegateTarget );
				$filter.toggleClass( 'open', ! $filter.hasClass( 'open' ) );
			}
		},

		/**
		 * Opens mobile version.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		openMobileFilters: function( e ) {
			$us.$body.addClass( 'us_filter_open' );
			this.$container.addClass( 'open' );
		},

		/**
		 * Close mobile version.
		 *
		 * @event handler
		 * @param {Event} e The Event interface represents an event which takes place in the DOM.
		 */
		closeMobileFilters: function() {
			$us.$body.removeClass( 'us_filter_open' );
			this.$container.removeClass( 'open' );
		},

		/**
		 * Enables or disables the mobile version.
		 *
		 * @event handler
		 */
		resize: function() {
			const self = this;
			let isMobile = $ush.parseInt( $us.$window.width() ) <= $ush.parseInt( self.settings.mobileWidth );

			if ( ! self.$container.hasClass( `state_${ isMobile ? 'mobile' : 'desktop' }` ) ) {
				self.$container.usMod( 'state', isMobile ? 'mobile' : 'desktop' );
				if ( ! isMobile ) {
					$us.$body.removeClass( 'us_filter_open' );
					self.$container.removeClass( 'open' );
				}
			}
		},

	} );

	$.fn.usListFilter = function() {
		return this.each( function() {
			$( this ).data( 'usListFilter', new usListFilter( this ) );
		} );
	};

	$( function() {
		$( '.w-filter.for_list' ).usListFilter();
	} );

}( jQuery );
