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

	const DELETE_FILTER = null;

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

		// Private "variables"
		self.data = {
			paged: 1,
			max_num_pages: 1,
			paginationBase: 'page',
			pagination: 'none',
			ajaxUrl: $us.ajaxUrl,
			ajaxData: {
				us_ajax_list_pagination: 1,
			},
			facetedFilter: {},
		};
		self.listFilterUid = null;
		self.isScrollToListEnabled = false;
		self.uid = $ush.uniqid();
		self.xhr;

		// Elements
		self.$container = $( container );
		self.$list = $( '.w-grid-list', container );
		self.$loadmore = $( '.g-loadmore', container );
		self.$pagination = $( 'nav.pagination', container );
		self.$none = self.$container.next( '.w-grid-none' );
		self.$pageContent = $( 'main#page-content' );

		self.isCurrentQuery = self.$container.hasClass( 'for_current_wp_query' );

		// Get element settings
		const $opts = $( '.w-grid-list-json:first', container );
		if ( $opts.is( '[onclick]' ) ) {
			$.extend( self.data, $opts[0].onclick() || {} );
		}
		$opts.remove();

		self.paginationType = $ush.toString( self.data.pagination );
		self.PAGE_URL_PATTERN = new RegExp( `\/${self.data.paginationBase}\/?([\\d]{1,})\/?` );

		// Bindable events
		self._events = {
			addNextPage: self.addNextPage.bind( self ),
			switchNumPage: self.switchNumPage.bind( self ),
			initMagnificPopup: self.initMagnificPopup.bind( self ),

			usListOrder: self.usListOrder.bind( self ),
			usListSearch: self.usListSearch.bind( self ),
			usListFilter: self.usListFilter.bind( self ),

			usbReloadIsotopeLayout: self.usbReloadIsotopeLayout.bind( self ),
		};

		// Load posts on button click, page scroll or numbered ajax
		if ( self.paginationType === 'load_on_btn' ) {
			self.$loadmore.on( 'mousedown', 'button', self._events.addNextPage );

		} else if ( self.paginationType === 'load_on_scroll' ) {
			$us.waypoints.add( self.$loadmore, /* offset */'-70%', self._events.addNextPage );

		} else if ( self.paginationType === 'numbered_ajax' ) {
			self.$container.on( 'click', 'a.page-numbers', self._events.switchNumPage );
		}

		// Events
		self.$container
			.add( self.$none )
			.on( 'usListSearch', self._events.usListSearch )
			.on( 'usListOrder', self._events.usListOrder )
			.on( 'usListFilter', self._events.usListFilter );
		self.$list
			.on( 'click', '[ref=magnificPopup]', self._events.initMagnificPopup )

		// Open posts in popup
		if ( self.$container.hasClass( 'open_items_in_popup' ) ) {
			self.popupPost = new $us.usPopup();
			self.popupPost.popupPost( self.$container );
		}

		// Initialize Masonry.
		// @see https://isotope.metafizzy.co
		if ( self.$container.hasClass( 'type_masonry' ) ) {
			self.$list.imagesLoaded( () => {

				const isotopeOptions = {
					itemSelector: '.w-grid-item',
					layoutMode: ( self.$container.hasClass( 'isotope_fit_rows' ) ) ? 'fitRows' : 'masonry',
					isOriginLeft: ! $( '.l-body' ).hasClass( 'rtl' ),
					transitionDuration: 0
				};

				var columnWidth;
				if ( $( '.size_1x1', self.$list ).length > 0 ) {
					columnWidth = '.size_1x1';
				} else if ( $( '.size_1x2', self.$list ).length > 0 ) {
					columnWidth = '.size_1x2';
				} else if ( $( '.size_2x1', self.$list ).length >0 ) {
					columnWidth = '.size_2x1';
				} else if ( $( '.size_2x2', self.$list ).length > 0 ) {
					columnWidth = '.size_2x2';
				}
				if ( columnWidth ) {
					columnWidth = columnWidth || '.w-grid-item';
					isotopeOptions.masonry = { columnWidth: columnWidth };
				}

				// Run CSS animations locally after rendering elements in Isotope.
				self.$list.on( 'layoutComplete', () => {
					if ( _window.USAnimate ) {
						$( '.w-grid-item.off_autostart', self.$list ).removeClass( 'off_autostart' );
						new USAnimate( self.$list );
					}
					// Trigger scroll event to check positions for `$us.waypoints`.
					$us.$window.trigger( 'scroll.waypoints' );
				} );

				self.$list.isotope( isotopeOptions );

				$us.$canvas.on( 'contentChange', () => {
					self.$list.imagesLoaded( () => {
						self.$list.isotope( 'layout' );
					} );
				} );
			} );

			self.$container.on( 'usbReloadIsotopeLayout', self._events.usbReloadIsotopeLayout );
		}

		// List Result Counter element
		self.initListResultCounter();
	}

	// Post List API
	$.extend( usPostList.prototype, {

		/**
		 * Set the search string from "List Search".
		 *
		 * @event handler
		 * @param {Event} e
		 * @param {String} name
		 * @param {String} value The search text.
		 */
		usListSearch: function( e, name, value ) {
			this.applyFilter( name, value );
		},

		/**
		 * Set orderby from "List Order".
		 *
		 * @event handler
		 * @param {Event} e
		 * @param {{}} values
		 */
		usListOrder: function( e, values ) {
			const self = this;
			$.each( values, self.applyFilter.bind( self ) );
		},

		/**
		 * Set values from "List Filter".
		 *
		 * @event handler
		 * @param {Event} e
		 * @param {{}} values
		 */
		usListFilter: function( e, values ) {
			const self = this;
			$.each( values, self.applyFilter.bind( self ) );
		},

		/**
		 * Add next page.
		 *
		 * @event handler
		 */
		addNextPage: function() {
			const self = this;
			if ( $ush.isUndefined( self.xhr ) && ! self.$none.is( ':visible' ) ) {
				self.data.paged += 1;
				self.addItems();
			}
		},

		/**
		 * Switch page for AJAX numbered pagination.
		 *
		 * @event handler
		 * @param {Event} e
		 */
		switchNumPage: function( e ) {
			const self = this;

			e.preventDefault();

			if ( $ush.isUndefined( self.xhr ) && self.$none.is( ':visible' ) ) {
				return;
			}

			const pageNum = $ush.parseInt(
				( $ush.toString( e.currentTarget.href ).match( self.PAGE_URL_PATTERN ) || [] )[1] || 1
			);

			self.setPageNumInHistory( pageNum );
			self.data.paged = pageNum;

			self.addItems();
		},

		/**
		 * Set page number in history.
		 *
		 * @param {Number} pageNum
		 */
		setPageNumInHistory: function ( pageNum ) {
			const self = this;

			const pathname = location.pathname;
			const isFirstPage = pageNum < 2;
			const pageStructure = `${self.data.paginationBase}/${pageNum}/`;

			var updatedPath;

			if ( self.PAGE_URL_PATTERN.test( pathname ) ) {
				updatedPath = isFirstPage
					? pathname.replace( self.PAGE_URL_PATTERN, '' ) + '/'
					: pathname.replace( self.PAGE_URL_PATTERN, '/' + pageStructure );

			} else if ( pageNum > 1 ) {
				updatedPath = pathname + pageStructure;

			} else {
				updatedPath = pathname
			}

			const method = isFirstPage ? 'pushState' : 'replaceState';
			history[ method ]( {}, '', location.href.replace( pathname, updatedPath ) );
		},

		/**
		 * Apply param to "Post/Product List".
		 *
		 * @param {String} name
		 * @param {String} value
		 */
		applyFilter: function( name, value ) {
			const self = this;
			if ( $ush.toString( value ) == '{}' ) {
				value = DELETE_FILTER;
			}

			// only save
			if ( name === 'list_filters' ) {
				$.extend( value, JSON.parse( self.data.ajaxData[ name ] || '{}' ) );
				self.data.ajaxData[ name ] = JSON.stringify( value );
				return;
			}
			if ( name === 'list_filter_uid' ) {
				self.listFilterUid = value;
				return;
			}
			if ( name === 'scroll_to_list' ) {
				self.isScrollToListEnabled = value;
				return;
			}

			// Reset pagination
			self.setPageNumInHistory(1);
			self.data.paged = 1;

			if ( self.isCurrentQuery ) {
				self.data.ajaxUrl = $ush
					.urlManager( self.data.ajaxUrl )
					.set( name, value )
					.toString();

			} else if ( value === DELETE_FILTER ) {
				delete self.data.ajaxData[ name ];

			} else {
				self.data.ajaxData[ name ] = value;
			}

			if ( ! $ush.isUndefined( self.xhr ) ) {
				self.xhr.abort();
			}
			self.addItems( /* apply filter */true );
		},

		/**
		 * Scrolls to the beginning of the list.
		 */
		scrollToList: function() {
			const self = this;

			if ( self.data.paged > 1 || ! self.isScrollToListEnabled ) {
				return;
			}

			const offsetTop = $ush.parseInt( self.$container.offset().top );
			if ( ! offsetTop ) {
				return;
			}

			const scrollTop = $us.$window.scrollTop();

			if (
				! $ush.isNodeInViewport( self.$container[0] )
				|| offsetTop >= ( scrollTop + window.innerHeight )
				|| scrollTop >= offsetTop
			) {
				$us.$htmlBody
					.stop( true, false )
					.animate( { scrollTop: ( offsetTop - $us.header.getInitHeight() ) }, 500 );
			}
		},

		/**
		 * Add items to element.
		 *
		 * @param {Boolean} listFiltersApplied
		 */
		addItems: function( listFiltersApplied ) {
			const self = this;

			if ( ! listFiltersApplied && self.data.paged > self.data.max_num_pages ) {
				return;
			}

			self.$container.removeClass( 'no_results' ).addClass( 'loading_items' );

			if ( listFiltersApplied ) {
				self.$container.addClass( 'filtering' );
				self.$loadmore.removeClass( 'hidden' );
			}

			// Get request link and data
			var ajaxUrl = $ush.toString( self.data.ajaxUrl ),
				ajaxData = $ush.clone( self.data.ajaxData ),
				numPage = $ush.rawurlencode( '{num_page}' );

			if ( ajaxUrl.includes( numPage ) ) {
				ajaxUrl = ajaxUrl.replace( numPage, self.data.paged );

			} else if ( ajaxData.template_vars ) {
				ajaxData.template_vars = JSON.stringify( ajaxData.template_vars ); // convert for `us_get_HTTP_POST_json()`
				ajaxData.paged = self.data.paged;
			}

			self.xhr = $.ajax( {
				type: 'post',
				url: ajaxUrl,
				dataType: 'html',
				cache: false,
				data: ajaxData,
				success: ( html ) => {

					// Remove previous items when filtered
					if ( listFiltersApplied ) {
						if ( self.$container.hasClass( 'type_masonry' ) ) {
							self.$list
								.isotope( 'remove', $( '.w-grid-item', self.$list ) )
								.isotope( 'layout' );
						}
						self.$list.html('');
						self.$none.addClass( 'hidden' );
					}

					// Get and set navigation from the response
					if ( self.paginationType == 'numbered_ajax' ) {
						const numPagination = $ush.toString( $( 'nav.pagination.navigation', html ).html() );

						self.$pagination
							.toggleClass( 'hidden', ! numPagination )
							.html( numPagination );

						self.$list.html('');
					}
					
					// Reload element settings
					var $listJson = $( '.w-grid-list-json:first', html );
					if ( $listJson.is( '[onclick]' ) ) {

						// Fix for WP Rocket "Delay JavaScript execution", see issue #5131
						if ( $listJson[0].onclick === null ) {
							$listJson[0].onclick = new Function( $listJson.attr( 'onclick' ) );
						}
						$.extend( true, self.data, $listJson[0].onclick() || {} );
					}

					var $items = $( html ).find( '.w-grid-list' ).first().children();

					// List items loaded
					$ush.timeout( () => {
						const data = {
							postListUid: self.uid,
							listFilterUid: self.listFilterUid,
							listFiltersApplied: listFiltersApplied,
						};
						// NOTE: Use `$items` as the first argument to ensure backward compatibility with custom solutions.
						$us.$document.trigger( 'usPostList.itemsLoaded', [ $items, data ] );
					}, 50 );

					// Case when there are no results
					if ( ! $items.length ) {

						if ( ! self.$none.length ) {
							self.$none = $( '.w-grid-none:first', html );
							if ( ! self.$none.length ) {
								self.$none = $( html ).filter( '.w-grid-none:first' );
							}
							self.$container.after( self.$none );
						}

						self.$container.removeClass( 'loading_items filtering' ).addClass( 'no_results' );
						self.$none.removeClass( 'hidden' );
						return;
					}

					// Output list items
					if ( self.$container.hasClass( 'type_masonry' ) ) {
						self.$list
							.isotope( 'insert', $items )
							.isotope( 'reloadItems' );
					} else {
						self.$list.append( $items );
					}

					// Init animation handler for new items
					if ( window.USAnimate && self.$container.hasClass( 'with_css_animation' ) ) {
						new USAnimate( self.$list );
						$us.$window.trigger( 'scroll.waypoints' );
					}

					// Case with numbered pagination
					if ( self.paginationType == 'numbered' ) {
						const $pagination = $( 'nav.pagination', html );

						if ( $pagination.length && ! self.$pagination.length ) {
							self.$list.after( $pagination.prop( 'outerHTML' ) );
							self.$pagination = self.$list.next( 'nav.pagination' );
						}

						if ( self.$pagination.length && $pagination.length ) {
							self.$pagination.html( $pagination.html() ).removeClass( 'hidden' );

						} else {
							self.$pagination.addClass( 'hidden' );
						}
					}

					// Case when the last page is loaded
					if ( self.data.paged >= self.data.max_num_pages ) {
						self.$loadmore.addClass( 'hidden' );

					} else {
						self.$loadmore.removeClass( 'hidden' );
					}

					// Add point to load the next page
					if ( self.paginationType === 'load_on_scroll' ) {
						$us.waypoints.add( self.$loadmore, /* offset */'-70%', self._events.addNextPage );
					}

					$us.$canvas.trigger( 'contentChange' );
				},
				complete: () => {
					self.$container.removeClass( 'loading_items filtering' );

					delete self.xhr;

					// Check if we need to load next page instantly for load on scroll
					if ( self.paginationType === 'load_on_scroll' ) {
						$us.$window.trigger( 'scroll.waypoints' );
					}

					// Scroll to top of list
					self.scrollToList();
				}
			} );
		},

		/**
		 * Reload layout in the Live Builder context.
		 *
		 * @event handler
		 */
		usbReloadIsotopeLayout: function() {
			const self = this;
			if ( self.$container.hasClass( 'with_isotope' ) ) {
				self.$list.isotope( 'layout' );
			}
		},
	} );

	// List Result Counter functionality
	$.extend( usPostList.prototype, {

		/**
		 * Initializing List Result Counter.
		 */
		initListResultCounter: function() {
			const self = this;
			const listResultCounterOpts = [];

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

			// Elements
			self.$listResultCounter = $( '.w-list-result-counter' );

			if ( ! ( self.$listResultCounter.length ) ) {
				return;
			}

			// Load options
			self.$listResultCounter.each( ( _, node ) => {
				const $node = $( node );

				if ( ! $node.is( '[onclick]' ) ) {
					return;
				}

				const opts = node.onclick() || {};

				/*
				* Determine the list to count
				* First List on page is used as default
				*/
				if ( self.$container[0] !== $firstList[0] ) {
					if ( ! self.$container.is( String( opts.listSelectorToCount ) ) ) {
						return;
					}

				} else if ( opts.listSelectorToCount && ! self.$container.is( String( opts.listSelectorToCount ) ) ) {
					return;
				}

				// Set node to count
				opts.$listResultCounter = $node;

				listResultCounterOpts.push( opts );
			} );

			// Events
			self._events.updateCountResults = function ( _, $items, data ) {
				if ( data.postListUid === self.uid ) {
					$.each( listResultCounterOpts, ( _, opts ) => {
						const foundPosts = ( self.paginationType === 'none' )
							? $( '> *', self.$list ).length
							: self.data.ajaxData.found_posts;
						self.countResult( foundPosts, opts );
					} );
				}
			};
			$us.$document.on( 'usPostList.itemsLoaded', self._events.updateCountResults );

			const numAjaxParams = Object.keys( $ush.urlManager( self.data.ajaxUrl ).toJson( false ) ).length;

			// Get total unfiltered from Post/Product list $wp_query
			$.ajax( {
				url: $us.ajaxUrl,
				type: 'POST',
				dataType: 'json',
				data: {
					action: 'us_list_result_counter_total',
					query_args_unfiltered: self.data.facetedFilter.query_args_unfiltered,
				},
				success: ( res ) => {
					if ( ! res.success ) {
						console.error( res.data.message );
						return;
					}

					// Check it here because we need compare below even if value is 0
					$.each( listResultCounterOpts, ( _, opts ) => {
						var total;
						if ( res.data.total_unfiltered ) {
							total = res.data.total_unfiltered;
						} else if ( self.paginationType === 'none' ) {
							total = $( '> *', self.$list ).length;
						} else {
							total = self.data.ajaxData.found_posts;
						}
						$( '.total-unfiltered', opts.$listResultCounter ).text( total );
					} );

					// Always count result if global $wp_query different from Post/Product list $wp_query
					$.each( listResultCounterOpts, ( _, opts ) => {
						if (
							opts.totalUnfiltered !== res.data.total_unfiltered
							&& self.paginationType !== 'none'
							&& numAjaxParams <= 1
						) {
							self.countResult( self.data.ajaxData.found_posts, opts );
						}
					} );
				},
			} );

			// Always count result for pagination type "none" on load for correct [upper] result
			if ( self.paginationType === 'none' && numAjaxParams <= 1 ) {
				$.each( listResultCounterOpts, ( _, opts ) => {
					self.countResult( $( '> *', self.$list ).length, opts );
				} );
			}

			// Count result on load if filter is active
			if ( self.paginationType === 'numbered' ) {
				if ( ! ( numAjaxParams < 1 ) ) {
					$.each( listResultCounterOpts, ( _, opts ) => {
						self.countResult( self.data.ajaxData.found_posts, opts );
					} );
				}

			} else if ( ! ( numAjaxParams <= 1 ) ) {
				const total = ( self.paginationType === 'none' )
					? $( '> *', self.$list ).length
					: self.data.ajaxData.found_posts;
				$.each( listResultCounterOpts, ( _, opts ) => {
					self.countResult( total, opts );
				} );
			}
		},

		/**
		 * Counts the number of results ( List Result Counter element )
		 *
		 * @param {Number} total
		 * @param {Object} opts
		 */
		countResult: function( total, opts ) {
			const self = this;
			if (
				! self.$listResultCounter.length
				|| $us.usbPreview()
			) {
				return;
			}

			const $listResultCounter = opts.$listResultCounter;
			const $noResultsSpan = $( '.no-results', $listResultCounter );
			const $oneResultSpan = $( '.one-result', $listResultCounter );
			const $mainSpan = $( 'span:first-child', $listResultCounter );
			const perPage = self.isCurrentQuery ? opts.perPage : self.data.ajaxData.per_page;

			$listResultCounter.show();
			$mainSpan.removeClass( 'hidden' );
			$noResultsSpan.addClass( 'hidden' );
			$oneResultSpan.addClass( 'hidden' );

			const lower = [ 'load_on_scroll', 'load_on_btn' ].includes( self.paginationType )
				? 1
				: ( self.data.paged - 1 ) * perPage + 1;

			const upper = self.paginationType === 'none'
				? $( '> *', self.$list ).length
				: Math.min( total, self.data.paged * perPage );

			if ( total === 1 ) {
				$mainSpan.addClass( 'hidden' );
				$oneResultSpan.removeClass( 'hidden' );
			} else if ( total === 0 ) {
				if ( $noResultsSpan.length ) {
					$mainSpan.addClass( 'hidden' );
					$noResultsSpan.removeClass( 'hidden' );
				} else {
					$listResultCounter.hide();
				}
			} else {
				$( '.lower', $listResultCounter ).text( lower );
				$( '.upper', $listResultCounter ).text( upper );
				$( '.total', $listResultCounter ).text( total );
			}
		},
	} );

	// Popup window functionality
	$.extend( usPostList.prototype, {

		/**
		 * Initializing MagnificPopup for AJAX loaded items
		 *
		 * @param {Event} e
		 */
		initMagnificPopup: function( e ) {
			e.stopPropagation();
			e.preventDefault();
			const $target = $( e.currentTarget );
			if ( $target.data( 'magnificPopup' ) === _undefined ) {
				$target.magnificPopup( {
					type: 'image',
					mainClass: 'mfp-fade'
				} );
				$target.trigger( 'click' );
			}
		},
	} );

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

	$( () => $( '.w-grid.us_post_list, .w-grid.us_product_list' ).usPostList() );

} )( jQuery );
