(function($) {
	$( window ).on( 'elementor/frontend/init', () => {
		class ShowcaseWidget extends elementorModules.frontend.handlers.Base {
			getDefaultSettings() {
				return {
					selectors: {
						carousel: '.pp-showcase-preview',
						sliderWrap: '.pp-showcase-preview-wrap',
						item: '.pp-showcase-preview-item',
						navWrap: '.pp-showcase-navigation-items',
						nav: '.pp-showcase-navigation-item-wrap',
						videoPlay: '.pp-showcase .pp-video-play',
					},
					slidesPerView: {
						widescreen: 3,
						desktop: 3,
						laptop: 3,
						tablet_extra: 3,
						tablet: 2,
						mobile_extra: 2,
						mobile: 1
					}
				};
			}

			getDefaultElements() {
				const selectors = this.getSettings( 'selectors' );
				return {
					$carousel: this.$element.find( selectors.carousel ),
					$sliderWrap: this.$element.find( selectors.sliderWrap ),
					$item: this.$element.find( selectors.item ),
					$navWrap: this.$element.find( selectors.navWrap ),
					$nav: this.$element.find( selectors.nav ),
					$videoPlay: this.$element.find( selectors.videoPlay ),
				};
			}

			getSliderSettings( prop ) {
				const data = this.elements.$carousel.data( 'slider-settings' ) || {};
				return ( prop !== undefined ) ? data[ prop ] : data;
			}

			getSlidesCount() {
				return this.elements.$nav.length;
			}

			getDeviceSlidesPerView( device ) {
				const key = 'nav_items' + ( 'desktop' === device ? '' : '_' + device );
				return Math.min( this.getSlidesCount(), +this.getElementSettings( key ) || this.getSettings( 'slidesPerView' )[ device ] );
			}

			getCurrentNavDirection() {
				const pos       = this.getSliderSettings( 'preview_position' );
				const stackOn   = this.getSliderSettings( 'preview_stack' );
				const breakpoints = elementorFrontend.config.responsive.activeBreakpoints;

				if ( 'top' === pos || 'bottom' === pos ) {
					return 'horizontal';
				}

				if ( stackOn && breakpoints[ stackOn ] ) {
					if ( window.innerWidth <= breakpoints[ stackOn ].value ) {
						return 'horizontal';
					}
				}

				return 'vertical';
			}

			getMainSwiperOptions() {
				const es = this.getElementSettings();

				const swiperOptions = {
					slidesPerView:       1,
					slidesPerGroup:      1,
					loop:                'yes' === es.infinite_loop,
					speed:               es.animation_speed || 600,
					autoHeight:          'yes' === es.adaptive_height,
					effect:              es.effect || 'slide',
					watchSlidesProgress: true,
				};

				if ( 'fade' === swiperOptions.effect ) {
					swiperOptions.fadeEffect = { crossFade: true };
				}

				if ( 'yes' === es.arrows ) {
					swiperOptions.navigation = {
						prevEl: '.pp-arrow-prev-' + this.getID(),
						nextEl: '.pp-arrow-next-' + this.getID(),
					};
				}

				if ( 'yes' === es.dots ) {
					swiperOptions.pagination = {
						el:        '.swiper-pagination-' + this.getID(),
						type:      'bullets',
						clickable: true,
					};
				}

				if ( ! this.isEdit && 'yes' === es.autoplay ) {
					swiperOptions.autoplay = {
						delay:              es.autoplay_speed || 3000,
						disableOnInteraction: false,
						pauseOnMouseEnter:  'yes' === es.pause_on_hover,
					};
				}

				return swiperOptions;
			}

			getNavSwiperOptions() {
				const es         = this.getElementSettings();
				const direction  = this.getCurrentNavDirection();
				const isVertical = 'vertical' === direction;

				const swiperOptions = {
					direction:                direction,
					slidesPerView:            this.getDeviceSlidesPerView( 'desktop' ),
					slidesPerGroup:           1,
					loop:                     'yes' === es.infinite_loop,
					watchSlidesProgress:      true,
					centerInsufficientSlides: 'yes' === es.nav_center_mode,
				};

				// Breakpoints apply to horizontal nav only; vertical direction is
				// handled by the destroy/reinit in onResize().
				if ( ! isVertical ) {
					const breakpointsSettings = {};
					const breakpoints = elementorFrontend.config.responsive.activeBreakpoints;

					Object.keys( breakpoints ).forEach( breakpointName => {
						if ( 'widescreen' !== breakpointName ) {
							breakpointsSettings[ breakpoints[ breakpointName ].value ] = {
								slidesPerView:  this.getDeviceSlidesPerView( breakpointName ),
								slidesPerGroup: 1,
							};
						}
					} );

					swiperOptions.breakpoints = breakpointsSettings;
				}

				return swiperOptions;
			}


			bindEvents() {
				const es = this.getElementSettings();

				this.initSlider( 'yes' === es.scrollable_nav );

				this.initFancybox();
				this.initVideo();

				const $tabs = this.$element.closest( '.elementor-widget-n-tabs' );
				if ( $tabs.length ) {
					$tabs.on( 'click', '.e-n-tab-title', () => {
						setTimeout( () => this.refreshSwiper(), 60 );
					} );
					$tabs.on( 'keyup', '.e-n-tab-title', () => {
						setTimeout( () => this.refreshSwiper(), 60 );
					} );
				}

				$( window ).on( 'resize.pp-showcase-' + this.getID(), () => {
					this.onResize();
				} );
			}

			async initSlider( scrollableNav ) {
				const Swiper = elementorFrontend.utils.swiper;

				if ( scrollableNav ) {
					if ( 'vertical' === this.getCurrentNavDirection() ) {
						this.preSetNavHeight();
					} else {
						this.elements.$navWrap.css( 'height', '' );
					}

					this.navSwiper = await new Swiper( this.elements.$navWrap, this.getNavSwiperOptions() );

					const mainOptions  = this.getMainSwiperOptions();
					mainOptions.thumbs = { swiper: this.navSwiper };
					this.swiper        = await new Swiper( this.elements.$carousel, mainOptions );

					this.swiper.on( 'slideChange', () => {
						this.videoStop();
						this.syncNavToMain();
					} );
				} else {
					this.swiper = await new Swiper( this.elements.$carousel, this.getMainSwiperOptions() );
					this.initSliderNav();
				}
			}

			syncNavToMain() {
				if ( ! this.navSwiper ) {
					return;
				}

				const target = this.swiper.realIndex;

				if ( this.navSwiper.params.loop ) {
					this.navSwiper.slideToLoop( target );
				} else {
					this.navSwiper.slideTo( target );
				}
			}


			/**
			 * Measure one nav item's natural height by cloning it into an off-canvas
			 * isolated div (same width, no height constraints from the flex parent),
			 * then set the Swiper container height to exactly slidesPerView × itemHeight.
			 * This must be called BEFORE new Swiper() so the container has the right
			 * dimensions from the start.
			 */
			preSetNavHeight() {
				const firstWrap = this.elements.$navWrap.find( '.pp-showcase-navigation-item-wrap' ).first();
				if ( ! firstWrap.length ) {
					return;
				}

				// Clone into an off-canvas div with the same width but NO height constraints,
				// so the measurement reflects the item's true content height.
				const $measure = $( '<div>' ).css( {
					position:    'absolute',
					top:         '-9999px',
					left:        '-9999px',
					visibility:  'hidden',
					width:       this.elements.$navWrap.width() + 'px',
					height:      'auto',
					overflow:    'visible',
					pointerEvents: 'none',
				} ).appendTo( 'body' );

				const $clone = firstWrap.clone().css( {
					height:   'auto',
					position: 'static',
					display:  'block',
				} ).appendTo( $measure );

				const itemH = $clone.outerHeight( true ); // includes margins
				$measure.remove();

				if ( ! itemH ) {
					return;
				}

				const spv = Math.min( this.getSlidesCount(), this.getDeviceSlidesPerView( 'desktop' ) );
				this.elements.$navWrap.css( 'height', itemH * spv + 'px' );
			}

			initSliderNav() {
				const $nav   = this.elements.$nav;
				const swiper = this.swiper;

				$nav.removeClass( 'pp-active-slide' );
				$nav.eq( 0 ).addClass( 'pp-active-slide' );

				swiper.on( 'slideChange', () => {
					this.videoStop();
					$nav.removeClass( 'pp-active-slide' );
					$nav.eq( swiper.realIndex ).addClass( 'pp-active-slide' );
				} );

				$nav.each( ( index, el ) => {
					$( el ).on( 'click', ( e ) => {
						e.preventDefault();
						if ( swiper.params.loop ) {
							swiper.slideToLoop( index );
						} else {
							swiper.slideTo( index );
						}
					} );
				} );
			}

			onResize() {
				const es = this.getElementSettings();

				if ( 'yes' === es.scrollable_nav && this.navSwiper ) {
					const newDirection = this.getCurrentNavDirection();

					if ( this.navSwiper.params.direction !== newDirection ) {
						this.navSwiper.destroy( true, true );
						this.swiper.destroy( true, true );
						this.initSlider( true );
						return;
					}
				}

				this.refreshSwiper();
			}

			refreshSwiper() {
				try {
					if ( this.swiper ) {
						this.swiper.update();
					}
					if ( this.navSwiper ) {
						this.navSwiper.update();
					}
				} catch ( err ) {}
			}

			initFancybox() {
				const showcaseId     = this.elements.$carousel.attr( 'id' ),
					lightboxSelector = '.swiper-slide:not(.swiper-slide-duplicate) .pp-showcase-item-link[data-fancybox="' + showcaseId + '"]';

				if ( $( lightboxSelector ).length > 0 ) {
					$( lightboxSelector ).fancybox( {
						loop: true
					} );
				}
			}

			initVideo() {
				let self = this;

				this.elements.$videoPlay.off( 'click' ).on( 'click', function( e ) {
					e.preventDefault();

					let outerWrap   = $( this ).closest( '.pp-video' ),
						videoPlayer = $( this ).find( '.pp-video-player' );

					self.videoPlay( videoPlayer, outerWrap );
				} );
			}

			videoPlay( selector, outerWrap ) {
				let $iframe    = $( '<iframe/>' ),
					vidSrc     = selector.data( 'src' ),
					videoThumb = outerWrap.find( '.pp-video-thumb-wrap' );

				if ( 0 === selector.find( 'iframe' ).length ) {
					if ( outerWrap.hasClass( 'pp-video-type-youtube' ) || outerWrap.hasClass( 'pp-video-type-vimeo' ) || outerWrap.hasClass( 'pp-video-type-dailymotion' ) ) {
						$iframe.attr( 'src', vidSrc );
					}

					$iframe.attr( 'frameborder', '0' );
					$iframe.attr( 'allowfullscreen', '1' );
					$iframe.attr( 'allow', 'autoplay;encrypted-media;' );
					videoThumb.hide();
					selector.append( $iframe );

					if ( outerWrap.hasClass( 'pp-video-type-hosted' ) ) {
						let hostedVideoHtml = JSON.parse( outerWrap.data( 'hosted-html' ) );

						$iframe.on( 'load', function() {
							let hostedVideoIframe = $iframe.contents().find( 'body' );
							hostedVideoIframe.html( hostedVideoHtml );
							$iframe.contents().find( 'video' ).css( { 'width': '100%', 'height': '100%' } );
							$iframe.contents().find( 'video' ).attr( 'autoplay', 'autoplay' );
						} );
					}
				}
			}

			videoStop() {
				this.elements.$item.each( function() {
					let selector   = $( this ).find( '.pp-video-player' ),
						videoThumb = $( this ).find( '.pp-video-thumb-wrap' ),
						$iframe    = $( this ).find( 'iframe' );

					if ( selector.find( 'iframe' ).length ) {
						$iframe.remove();
						videoThumb.show();
					}
				} );
			}
		}

		elementorFrontend.elementsHandler.attachHandler( 'pp-showcase', ShowcaseWidget );
	} );
} )( jQuery );
