(function( $ ) {
	'use strict';

	var MinimogGridPlugin = function( $el, options ) {
		this.$el  = $el;
		var $grid = $el.find( '.minimog-grid' );

		var disableColumnChange      = false;
		var activeColumns            = 1,
		    activeGutter             = 0,
		    activeZigzagHeight       = 0,
		    activeAlternatingColumns = 0; // 0 to Disable, 1 to Enable, -1 to Enable & Reversed.

		this._isotopeOptions = {
			itemSelector: '.grid-item',
			percentPosition: true,
			transitionDuration: 0,
			packery: {
				columnWidth: '.grid-sizer',
			},
			fitRows: {
				gutter: 10
			}
		};

		// jQuery's methods.
		this.triggerMethod = ( method, options ) => {
			if ( typeof this[method] === 'function' ) {
				this[method]( options );
			}
		};

		this.init = function() {
			var plugin = this;
			var resizeTimer;

			var settings = $el.data( 'grid' );

			if ( $grid.length > 0 && settings && typeof settings.type !== 'undefined' ) {
				if ( $minimog.isRTL ) {
					plugin._isotopeOptions.originLeft = false;
				}

				if ( 'masonry' === settings.type || 'metro' === settings.type ) {
					plugin._isotopeOptions.layoutMode = 'packery';
				} else {
					plugin._isotopeOptions.layoutMode = 'fitRows';
				}

				plugin.calculateMasonrySize();

				var promises = window.minimog.Helpers.imagesLoaded( $grid );
				promises.length > 0 && Promise.all( promises ).then( ( values ) => {
					plugin.calculateMasonrySize();
				} );

				$( window ).on( 'hresize', function() {
					plugin.calculateMasonrySize();

					// Sometimes layout can be overlap. then re-cal layout one time.
					clearTimeout( resizeTimer );
					resizeTimer = setTimeout( function() {
						// Run code here, resizing has "stopped"
						plugin.calculateMasonrySize();
					}, 500 ); // DO NOT decrease the time. Sometime, It'll make layout overlay on resize.
				} );
			} else {
				$grid.addClass( 'loaded' );
			}

			$el.on( 'MinimogQueryEnd', function( event, el, $items ) {
				plugin.update( $items );
			} );
		};

		this.update = function( $items ) {
			var plugin   = this,
			    settings = $el.data( 'grid' );

			if ( $grid.length > 0 && settings && typeof settings.type !== 'undefined' ) {
				$grid.isotope().append( $items ).isotope( 'reloadItems', $items );

				plugin.calculateMasonrySize();

				var promises = window.minimog.Helpers.imagesLoaded( $items );
				promises.length > 0 && Promise.all( promises ).then( ( values ) => {
					plugin.calculateMasonrySize();
				} );
			} else {
				$grid.append( $items );
			}
		};

		this.updateLayout = function( options = {} ) {
			var plugin = this;

			plugin.disableColumnChange = true === options.disableColumnChange;

			plugin.calculateMasonrySize( options );
		};

		this.parseNumberValue = function( setting = '', default_value = '' ) {
			if ( undefined === setting || '' === setting || isNaN( setting ) ) {
				return default_value;
			}

			return parseInt( setting );
		};

		this.calculateMasonrySize = function( options = {} ) {
			var plugin   = this,
			    settings = $el.data( 'grid' );

			if ( ! settings ) {
				return;
			}

			var windowWidth             = window.innerWidth,
			    gridWidth               = $grid[0].getBoundingClientRect().width,

			    gutterDesktop           = this.parseNumberValue( settings.gutter, 0 ),
			    gutterWideScreen        = this.parseNumberValue( settings.gutterWideScreen, gutterDesktop ),
			    gutterLaptop            = this.parseNumberValue( settings.gutterLaptop, gutterDesktop ),
			    gutterTabletExtra       = this.parseNumberValue( settings.gutterTabletExtra, gutterLaptop ),
			    gutterTablet            = this.parseNumberValue( settings.gutterTablet, gutterTabletExtra ),
			    gutterMobileExtra       = this.parseNumberValue( settings.gutterMobileExtra, gutterTablet ),
			    gutterMobile            = this.parseNumberValue( settings.gutterMobile, gutterMobileExtra ),
			    columnsDesktop          = this.parseNumberValue( settings.columns, 1 ),
			    columnsWideScreen       = this.parseNumberValue( settings.columnsWideScreen, columnsDesktop ),
			    columnsLaptop           = this.parseNumberValue( settings.columnsLaptop, columnsDesktop ),
			    columnsTabletExtra      = this.parseNumberValue( settings.columnsTabletExtra, columnsLaptop ),
			    columnsTablet           = this.parseNumberValue( settings.columnsTablet, columnsTabletExtra ),
			    columnsMobileExtra      = this.parseNumberValue( settings.columnsMobileExtra, columnsTablet ),
			    columnsMobile           = this.parseNumberValue( settings.columnsMobile, columnsMobileExtra ),
			    zigzagHeightDesktop     = this.parseNumberValue( settings.zigzagHeight, 0 ),
			    zigzagHeightWideScreen  = this.parseNumberValue( settings.zigzagHeightWideScreen, zigzagHeightDesktop ),
			    zigzagHeightLaptop      = this.parseNumberValue( settings.zigzagHeightLaptop, zigzagHeightDesktop ),
			    zigzagHeightTabletExtra = this.parseNumberValue( settings.zigzagHeightTabletExtra, zigzagHeightLaptop ),
			    zigzagHeightTablet      = this.parseNumberValue( settings.zigzagHeightTablet, zigzagHeightTabletExtra ),
			    zigzagHeightMobileExtra = this.parseNumberValue( settings.zigzagHeightMobileExtra, zigzagHeightTablet ),
			    zigzagHeightMobile      = this.parseNumberValue( settings.zigzagHeightMobile, zigzagHeightMobileExtra ),
			    zigzagReversed          = settings.zigzagReversed !== undefined && settings.zigzagReversed === 1 ? true : false;

			var alternatingColumnWidth       = 0,
			    columnAlternatingDesktop     = this.parseNumberValue( settings.columnAlternating, 0 ),
			    columnAlternatingWideScreen  = this.parseNumberValue( settings.columnAlternatingWideScreen, columnAlternatingDesktop ),
			    columnAlternatingLaptop      = this.parseNumberValue( settings.columnAlternatingLaptop, columnAlternatingDesktop ),
			    columnAlternatingTabletExtra = this.parseNumberValue( settings.columnAlternatingTabletExtra, columnAlternatingLaptop ),
			    columnAlternatingTablet      = this.parseNumberValue( settings.columnAlternatingTablet, columnAlternatingTabletExtra ),
			    columnAlternatingMobileExtra = this.parseNumberValue( settings.columnAlternatingMobileExtra, columnAlternatingTablet ),
			    columnAlternatingMobile      = this.parseNumberValue( settings.columnAlternatingMobile, columnAlternatingMobileExtra );

			var wideScreenBreakPoint  = 1600;
			var laptopBreakPoint      = 1200;
			var tabletExtraBreakPoint = 992;
			var tabletBreakPoint      = 768;
			var mobileExtraBreakPoint = 576;
			var mobileBreakPoint      = 360;

			if ( typeof elementorFrontendConfig !== 'undefined' ) {
				var elementorBreakpoints = elementorFrontendConfig.responsive.breakpoints;

				wideScreenBreakPoint  =
					this.parseNumberValue( elementorBreakpoints.widescreen.value, wideScreenBreakPoint );
				laptopBreakPoint      = this.parseNumberValue( elementorBreakpoints.laptop.value, laptopBreakPoint );
				tabletExtraBreakPoint =
					this.parseNumberValue( elementorBreakpoints.tablet_extra.value, tabletExtraBreakPoint );
				tabletBreakPoint      = this.parseNumberValue( elementorBreakpoints.tablet.value, tabletBreakPoint );
				mobileExtraBreakPoint =
					this.parseNumberValue( elementorBreakpoints.mobile_extra.value, mobileBreakPoint );
				mobileBreakPoint      = this.parseNumberValue( elementorBreakpoints.mobile.value, mobileBreakPoint );
			}

			var oldActiveColumns = plugin.activeColumns;

			if ( ! plugin.disableColumnChange ) {
				if ( windowWidth >= wideScreenBreakPoint ) { // Use >= Because from up
					plugin.activeColumns            = columnsWideScreen;
					plugin.activeGutter             = gutterWideScreen;
					plugin.activeZigzagHeight       = zigzagHeightWideScreen;
					plugin.activeAlternatingColumns = columnAlternatingWideScreen;
				} else if ( windowWidth > laptopBreakPoint ) {
					plugin.activeColumns            = columnsDesktop;
					plugin.activeGutter             = gutterDesktop;
					plugin.activeZigzagHeight       = zigzagHeightDesktop;
					plugin.activeAlternatingColumns = columnAlternatingDesktop;
				} else if ( windowWidth > tabletExtraBreakPoint ) {
					plugin.activeColumns            = columnsLaptop;
					plugin.activeGutter             = gutterLaptop;
					plugin.activeZigzagHeight       = zigzagHeightLaptop;
					plugin.activeAlternatingColumns = columnAlternatingLaptop;
				} else if ( windowWidth > tabletBreakPoint ) {
					plugin.activeColumns            = columnsTabletExtra;
					plugin.activeGutter             = gutterTabletExtra;
					plugin.activeZigzagHeight       = zigzagHeightTabletExtra;
					plugin.activeAlternatingColumns = columnAlternatingTabletExtra;
				} else if ( windowWidth > mobileExtraBreakPoint ) {
					plugin.activeColumns            = columnsTablet;
					plugin.activeGutter             = gutterTablet;
					plugin.activeZigzagHeight       = zigzagHeightTablet;
					plugin.activeAlternatingColumns = columnAlternatingTablet;
				} else if ( windowWidth > mobileBreakPoint ) {
					plugin.activeColumns            = columnsMobileExtra;
					plugin.activeGutter             = gutterMobileExtra;
					plugin.activeZigzagHeight       = zigzagHeightMobileExtra;
					plugin.activeAlternatingColumns = columnAlternatingMobileExtra;
				} else {
					plugin.activeColumns            = columnsMobile;
					plugin.activeGutter             = gutterMobile;
					plugin.activeZigzagHeight       = zigzagHeightMobile;
					plugin.activeAlternatingColumns = columnAlternatingMobile;
				}
			}

			/**
			 * Override Columns.
			 */
			if ( typeof options.columns !== 'undefined' ) {
				plugin.activeColumns = options.columns;
			}

			if ( oldActiveColumns !== plugin.activeColumns ) {
				$( document.body ).trigger( 'MinimogGridLayoutColumnsChange', [
					$el, oldActiveColumns, plugin.activeColumns
				] );
			}

			$el.attr( 'data-active-columns', plugin.activeColumns );

			var totalGutterPerRow = (plugin.activeColumns - 1) * plugin.activeGutter;

			var columnWidth = (gridWidth - totalGutterPerRow) / plugin.activeColumns;

			columnWidth = Math.floor( columnWidth );

			var columnWidth2 = columnWidth;
			if ( plugin.activeColumns > 1 ) {
				columnWidth2 = columnWidth * 2 + plugin.activeGutter;
			}

			/**
			 * Used this css var for layout grid border around
			 */
			var realWidth = columnWidth * plugin.activeColumns + plugin.activeGutter * (plugin.activeColumns - 1);
			$el.css( '--grid-real-width', realWidth + 'px' );

			$grid.children( '.grid-sizer' ).css( {
				'width': columnWidth + 'px'
			} );

			var columnHeight   = 0,
			    columnHeight2  = 0, // 200%.
			    columnHeight7  = 0, // 70%.
			    columnHeight13 = 0, // 130%.
			    isMetro        = false,
			    ratioW         = 1,
			    ratioH         = 1;

			if ( settings.ratio ) {
				ratioH  = settings.ratio;
				isMetro = true;
			}

			// Calculate item height for only metro type.
			if ( isMetro ) {
				columnHeight = columnWidth * ratioH / ratioW;
				columnHeight = Math.floor( columnHeight );

				if ( plugin.activeColumns > 1 ) {
					columnHeight2  = columnHeight * 2 + plugin.activeGutter;
					columnHeight13 = parseInt( columnHeight * 1.3 );
					columnHeight7  = columnHeight2 - plugin.activeGutter - columnHeight13;
				} else {
					columnHeight2 = columnHeight7 = columnHeight13 = columnHeight;
				}
			}

			var alternatingLoopCount        = 0;
			var alternatingReversed         = plugin.activeAlternatingColumns < 0 ? true : false;
			var totalAlternatingColumns     = alternatingReversed ? plugin.activeColumns - 1 : plugin.activeColumns + 1;
			var totalAlternatingFlowColumns = plugin.activeColumns + totalAlternatingColumns; // Normal columns + alternating columns.
			var isAlternatingColumn         = false;

			if ( plugin.activeAlternatingColumns ) {
				if ( alternatingReversed ) {
					alternatingColumnWidth =
						(gridWidth - (totalAlternatingColumns - 1) * plugin.activeGutter) / totalAlternatingColumns;
				} else {
					alternatingColumnWidth =
						(gridWidth - plugin.activeColumns * plugin.activeGutter) / (plugin.activeColumns + 1);
				}

				alternatingColumnWidth = Math.floor( alternatingColumnWidth );
			}

			$grid.children( '.grid-item' ).each( function( index ) {
				var gridItem = $( this );
				alternatingLoopCount ++;

				if ( alternatingLoopCount > plugin.activeColumns ) {
					isAlternatingColumn = true;
				}

				// Zigzag.
				if ( plugin.activeZigzagHeight > 0 // Has zigzag.
				     && plugin.activeColumns > 1 // More than 1 column.
				     && index + 1 <= plugin.activeColumns // On top items.
				) {
					if ( zigzagReversed === false ) { // Is odd item.
						if ( index % 2 === 0 ) {
							gridItem.css( {
								'marginTop': plugin.activeZigzagHeight + 'px'
							} );
						} else {
							gridItem.css( {
								'marginTop': '0px'
							} );
						}
					} else {
						if ( index % 2 !== 0 ) {
							gridItem.css( {
								'marginTop': plugin.activeZigzagHeight + 'px'
							} );
						} else {
							gridItem.css( {
								'marginTop': '0px'
							} );
						}
					}

				} else {
					gridItem.css( {
						'marginTop': '0px'
					} );
				}

				if ( plugin.activeAlternatingColumns && isAlternatingColumn ) {
					gridItem.css( {
						'width': alternatingColumnWidth + 'px',
						'height': 'auto',
					} );
				} else {
					if ( gridItem.data( 'width' ) === 2 ) {
						gridItem.css( {
							'width': columnWidth2 + 'px',
							'height': 'auto',
						} );
					} else {
						gridItem.css( {
							'width': columnWidth + 'px',
							'height': 'auto',
						} );
					}
				}

				if ( 'grid' === settings.type ) {
					gridItem.css( {
						'marginBottom': plugin.activeGutter + 'px'
					} );
				}

				if ( isMetro ) {
					var $itemHeight;

					if ( gridItem.hasClass( 'grid-item-height' ) ) {
						$itemHeight = gridItem;
					} else {
						$itemHeight = gridItem.find( '.grid-item-height' );
					}

					if ( gridItem.data( 'height' ) === 2 ) {
						$itemHeight.css( {
							'height': columnHeight2 + 'px'
						} );
					} else if ( gridItem.data( 'height' ) === 1.3 ) {
						$itemHeight.css( {
							'height': columnHeight13 + 'px'
						} );
					} else if ( gridItem.data( 'height' ) === 0.7 ) {
						$itemHeight.css( {
							'height': columnHeight7 + 'px'
						} );
					} else {
						$itemHeight.css( {
							'height': columnHeight + 'px'
						} );
					}
				}

				isAlternatingColumn = false;
				if ( alternatingLoopCount % totalAlternatingFlowColumns === 0 ) {
					alternatingLoopCount = 0; // Reset to next alternating row.
				}
			} );

			if ( plugin._isotopeOptions ) {
				$grid.addClass( 'loaded' );
				plugin._isotopeOptions.packery.gutter = plugin.activeGutter;
				plugin._isotopeOptions.fitRows.gutter = plugin.activeGutter;
				$grid.isotope( plugin._isotopeOptions );
			}

			// Run after isotope function to fix overlap layout.
			if ( 'grid' === settings.type ) {
				$grid.children( '.grid-item' ).matchHeight();
			}

			/**
			 * Delay 250 to fix layout overlap when toggle columns.
			 */
			setTimeout( function() {
				$grid.isotope( 'layout' );
				$el.trigger( 'MinimogGridLayoutResized' );
			}, 250 );
		};
		this.init();
	};

	const namespace = 'minimogGridLayout';

	$.fn.extend( {
		MinimogGridLayout: function( args, update ) {
			// Check if selected element exist.
			if ( ! this.length ) {
				return this;
			}

			// We need to return options.
			if ( args === 'options' ) {
				return $.data( this.get( 0 ), namespace ).options();
			}

			return this.each( function() {
				var $el = $( this );

				let instance = $.data( this, namespace );

				if ( instance ) { // Already created then trigger method.
					instance.triggerMethod( args, update );
				} else { // Create new instance.
					instance = new MinimogGridPlugin( $el, args );
					$.data( this, namespace, instance );
				}
			} );
		}
	} );
}( jQuery ));
