import isNumber from 'is-number';
import $ from 'jquery';

const $doc = $( document );
const { screenSizes } = window.VPData;

function getSwiperVersion( Swiper ) {
	let ver = 8;

	// in version 8 added new parameter `maxBackfaceHiddenSlides`.
	if ( typeof Swiper.defaults.maxBackfaceHiddenSlides === 'undefined' ) {
		ver = 7;
	}

	// in version 7 added new parameter `rewind`.
	if ( typeof Swiper.defaults.rewind === 'undefined' ) {
		ver = 6;
	}

	// in version 6 added new parameter `loopPreventsSlide`.
	if ( typeof Swiper.defaults.loopPreventsSlide === 'undefined' ) {
		ver = 5;
	}

	return ver;
}

// Extend VP class.
$doc.on( 'extendClass.vpf', ( event, VP ) => {
	if ( event.namespace !== 'vpf' ) {
		return;
	}

	/**
	 * Init Swiper plugin
	 *
	 * @param {mixed} options - slider options.
	 */
	VP.prototype.initSwiper = function ( options = false ) {
		const self = this;

		if (
			self.options.layout === 'slider' &&
			typeof window.Swiper !== 'undefined'
		) {
			const $parent = self.$items_wrap.parent();

			$parent.addClass( 'swiper' );
			self.$items_wrap.addClass( 'swiper-wrapper' );
			self.$items_wrap.children().addClass( 'swiper-slide' );

			// calculate responsive.
			let slidesPerView = self.options.sliderSlidesPerView || 3;
			const breakPoints = {};

			if ( self.options.sliderEffect === 'fade' ) {
				slidesPerView = 1;
			}

			if ( isNumber( slidesPerView ) ) {
				let count = slidesPerView;
				let currentPoint = Math.min(
					screenSizes.length - 1,
					count - 1
				);

				for ( ; currentPoint >= 0; currentPoint -= 1 ) {
					if (
						count > 0 &&
						typeof screenSizes[ currentPoint ] !== 'undefined'
					) {
						breakPoints[ screenSizes[ currentPoint ] + 1 ] = {
							slidesPerView: count,
						};
					}
					count -= 1;
				}

				slidesPerView = count || 1;
			}

			let optionsThumbs = false;
			let $thumbsParent = false;
			options = options || {
				speed: ( parseFloat( self.options.sliderSpeed ) || 0 ) * 1000,
				autoHeight: self.options.sliderItemsHeight === 'auto',
				effect: self.options.sliderEffect || 'slide',
				// fix fade items collapse (mostly in Default items style).
				fadeEffect: {
					crossFade: true,
				},
				spaceBetween: parseFloat( self.options.itemsGap ) || 0,
				centeredSlides: self.options.sliderCenteredSlides === 'true',
				freeMode: {
					enabled: self.options.sliderFreeMode === 'true',
					sticky: self.options.sliderFreeModeSticky === 'true',
				},
				loop: self.options.sliderLoop === 'true',
				// This feature is cool, but not working properly when loop enabled
				// and fast clicking on previous button is not working properly
				// https://github.com/nolimits4web/swiper/issues/5945
				// loopPreventsSlide: false,
				autoplay: parseFloat( self.options.sliderAutoplay ) > 0 && {
					delay: parseFloat( self.options.sliderAutoplay ) * 1000,
					disableOnInteraction: false,
				},
				navigation: self.options.sliderArrows === 'true' && {
					nextEl: '.vp-portfolio__items-arrow-next',
					prevEl: '.vp-portfolio__items-arrow-prev',
				},
				pagination: self.options.sliderBullets === 'true' && {
					el: '.vp-portfolio__items-bullets',
					clickable: true,
					dynamicBullets:
						self.options.sliderBulletsDynamic === 'true',
					renderBullet( index, className ) {
						return `<span class="${ className }" data-bullet-index="${ index }" data-bullet-number="${
							index + 1
						}"></span>`;
					},
				},
				mousewheel: self.options.sliderMousewheel === 'true',
				slidesPerView,
				breakpoints: breakPoints,
				keyboard: true,
				grabCursor: true,
				preloadImages: false,

				// fixes text selection when swipe in the items gap.
				touchEventsTarget: 'container',
			};

			// fix first load slide position (seems like a conflict with lazySizes)
			// issue: https://github.com/nk-crew/visual-portfolio/issues/54
			if ( options.speed === 0 ) {
				options.speed = 1;
			}
			let positionFix = 0;

			options.on = {
				transitionEnd() {
					if ( positionFix === 0 ) {
						positionFix = 1;
						this.setTransition( 1 );
						this.setTranslate( this.translate + 0.1 );
					} else if ( positionFix === 1 ) {
						positionFix = 2;
						this.slideReset();
					}
				},
				// These events used to add fixes for
				// conflict with custom cursor movement.
				touchStart( swiper, e ) {
					self.emitEvent( 'swiperTouchStart', [ swiper, e ] );
				},
				touchMove( swiper, e ) {
					self.emitEvent( 'swiperTouchMove', [ swiper, e ] );
				},
				touchEnd( swiper, e ) {
					self.emitEvent( 'swiperTouchEnd', [ swiper, e ] );
				},
			};

			self.emitEvent( 'beforeInitSwiper', [ options ] );

			// thumbnails.
			if ( self.$slider_thumbnails_wrap.length ) {
				$thumbsParent = self.$slider_thumbnails_wrap.parent();

				$thumbsParent.addClass( 'swiper' );
				self.$slider_thumbnails_wrap.addClass( 'swiper-wrapper' );
				self.$slider_thumbnails_wrap
					.children()
					.addClass( 'swiper-slide' );

				// calculate responsive.
				let thumbnailsPerView =
					self.options.sliderThumbnailsPerView || 8;
				const thumbnailsBreakPoints = {};

				if ( isNumber( thumbnailsPerView ) ) {
					let count = thumbnailsPerView;
					let currentPoint = Math.min(
						screenSizes.length - 1,
						count - 1
					);

					for ( ; currentPoint >= 0; currentPoint -= 1 ) {
						if (
							count > 0 &&
							typeof screenSizes[ currentPoint ] !== 'undefined'
						) {
							thumbnailsBreakPoints[
								screenSizes[ currentPoint ] + 1
							] = {
								slidesPerView: count,
							};
						}
						count -= 1;
					}

					thumbnailsPerView = count || 1;
				}

				optionsThumbs = {
					autoHeight: self.options.sliderThumbnailsHeight === 'auto',
					effect: 'slide',
					spaceBetween:
						parseFloat( self.options.sliderThumbnailsGap ) || 0,
					loop: false,
					// This feature is cool, but not working properly when loop enabled
					// and fast clicking on previous button is not working properly
					// https://github.com/nolimits4web/swiper/issues/5945
					// loopPreventsSlide: false,
					freeMode: {
						enabled: true,
						sticky: true,
					},
					loopedSlides: 5,
					slidesPerView: thumbnailsPerView,
					breakpoints: thumbnailsBreakPoints,
					keyboard: true,
					grabCursor: true,
					watchSlidesVisibility: true,
					watchSlidesProgress: true,
					preloadImages: false,

					// fixed text selection when swipe in the items gap.
					touchEventsTarget: 'container',
					on: {
						// These events used to add fixes for
						// conflict with custom cursor movement.
						touchStart( swiper, e ) {
							self.emitEvent( 'swiperTouchStart', [ swiper, e ] );
						},
						touchMove( swiper, e ) {
							self.emitEvent( 'swiperTouchMove', [ swiper, e ] );
						},
						touchEnd( swiper, e ) {
							self.emitEvent( 'swiperTouchEnd', [ swiper, e ] );
						},
					},
				};
			}

			// Fallbacks for old Swiper versions.
			( () => {
				const swiperVersion = getSwiperVersion( window.Swiper );
				const isThumbsEnabled =
					optionsThumbs && $thumbsParent && $thumbsParent[ 0 ];

				// Since v7 used container class `swiper`, we should also add old `swiper-container` class.
				if ( swiperVersion < 7 ) {
					$parent.addClass( 'swiper-container' );

					if ( isThumbsEnabled ) {
						$thumbsParent.addClass( 'swiper-container' );
					}
				}

				// Since v7 freeMode options moved under `freeMode` object.
				if ( swiperVersion < 7 ) {
					options.freeModeSticky = options.freeMode.sticky;
					options.freeMode = options.freeMode.enabled;

					if ( isThumbsEnabled ) {
						optionsThumbs.freeModeSticky =
							optionsThumbs.freeMode.sticky;
						optionsThumbs.freeMode = optionsThumbs.freeMode.enabled;
					}
				}

				// Since v5 `breakpointsInverse` option is removed and it is now `true` by default, but in older versions it was `false`.
				if ( swiperVersion >= 5 ) {
					options.breakpointsInverse = true;

					if ( isThumbsEnabled ) {
						optionsThumbs.breakpointsInverse = true;
					}
				}
			} )();

			// Init Swiper.
			if ( optionsThumbs && $thumbsParent && $thumbsParent[ 0 ] ) {
				const swiperThumbs = new window.Swiper(
					$thumbsParent[ 0 ],
					optionsThumbs
				);

				options.thumbs = {
					swiper: swiperThumbs,
				};
			}
			const instance = new window.Swiper( $parent[ 0 ], options );

			// Autoplay Hover Pause.
			if (
				self.options.sliderAutoplayHoverPause === 'true' &&
				parseFloat( self.options.sliderAutoplay ) > 0
			) {
				self.$item.on(
					`mouseenter.vpf-uid-${ self.uid }`,
					'.swiper',
					() => {
						$parent[ 0 ].swiper.autoplay.stop();
					}
				);
				self.$item.on(
					`mouseleave.vpf-uid-${ self.uid }`,
					'.swiper',
					() => {
						$parent[ 0 ].swiper.autoplay.start();
					}
				);
			}

			self.emitEvent( 'initSwiper', [ options, instance ] );
		}
	};

	/**
	 * Destroy Swiper plugin
	 */
	VP.prototype.destroySwiper = function () {
		const self = this;
		const $parent = self.$items_wrap.parent();
		const $thumbsParent = self.$slider_thumbnails_wrap.length
			? self.$slider_thumbnails_wrap.parent()
			: false;

		const SliderSwiper = $parent[ 0 ].swiper;
		const ThumbsSwiper = $thumbsParent ? $thumbsParent[ 0 ].swiper : false;

		let isDestroyed = false;

		// Thumbnails.
		if ( ThumbsSwiper ) {
			ThumbsSwiper.destroy();

			$thumbsParent.removeClass( 'swiper' );
			self.$slider_thumbnails_wrap.removeClass( 'swiper-wrapper' );
			self.$slider_thumbnails_wrap
				.children()
				.removeClass( 'swiper-slide' );

			isDestroyed = true;
		}

		// Slider.
		if ( SliderSwiper ) {
			SliderSwiper.destroy();

			$parent.removeClass( 'swiper' );
			self.$items_wrap.removeClass( 'swiper-wrapper' );
			self.$items_wrap.children().removeClass( 'swiper-slide' );

			$parent
				.find( '.vp-portfolio__items-bullets' )
				.removeClass(
					'swiper-pagination-clickable swiper-pagination-bullets-dynamic'
				)
				.removeAttr( 'style' )
				.html( '' );

			isDestroyed = true;
		}

		if ( isDestroyed ) {
			self.emitEvent( 'destroySwiper' );
		}
	};
} );

// Add Items.
$doc.on( 'addItems.vpf', ( event, self, $items, removeExisting, $newVP ) => {
	if ( event.namespace !== 'vpf' ) {
		return;
	}

	const Swiper = self.$items_wrap.parent()[ 0 ].swiper;

	if ( ! Swiper ) {
		return;
	}

	// Slider.
	{
		if ( removeExisting ) {
			Swiper.removeAllSlides();
		}

		const appendArr = [];
		$items.addClass( 'swiper-slide' ).each( function () {
			appendArr.push( this );
		} );
		Swiper.appendSlide( appendArr );
	}

	// Thumbnails.
	const ThumbsSwiper = self.$slider_thumbnails_wrap.length
		? self.$slider_thumbnails_wrap.parent()[ 0 ].swiper
		: false;
	if ( ThumbsSwiper ) {
		if ( removeExisting ) {
			ThumbsSwiper.removeAllSlides();
		}

		const appendArr = [];
		$newVP
			.find( '.vp-portfolio__thumbnails > .vp-portfolio__thumbnail-wrap' )
			.clone()
			.addClass( 'swiper-slide' )
			.each( function () {
				appendArr.push( this );
			} );
		ThumbsSwiper.appendSlide( appendArr );
	}
} );

// Init.
$doc.on( 'init.vpf', ( event, self ) => {
	if ( event.namespace !== 'vpf' ) {
		return;
	}

	self.initSwiper();
} );

// Destroy.
$doc.on( 'destroy.vpf', ( event, self ) => {
	if ( event.namespace !== 'vpf' ) {
		return;
	}

	self.destroySwiper();
} );
