import $ from 'jquery';
import rafSchd from 'raf-schd';
import { debounce, throttle } from 'throttle-debounce';

const { getComputedStyle } = window;
const $wnd = $( window );
const $doc = $( document );

const SUPPORTED_LAYOUTS = [ 'tiles', 'masonry', 'grid' ];

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

	/**
	 * Init Isotope
	 * TODO: Check one of these scripts as alternative
	 * - https://github.com/haltu/muuri
	 * - https://github.com/Vestride/Shuffle
	 * - https://github.com/patrickkunka/mixitup
	 *
	 * @param {Object} options isotope options
	 */
	VP.prototype.initIsotope = function ( options ) {
		const self = this;

		if (
			self.$items_wrap.isotope &&
			SUPPORTED_LAYOUTS.includes( self.options.layout )
		) {
			const isRtl =
				getComputedStyle( self.$items_wrap[ 0 ] ).direction === 'rtl';

			const initOptions = options || {
				itemSelector: '.vp-portfolio__item-wrap',
				layoutMode: 'masonry',
				masonry:
					self.options.layout === 'masonry'
						? {
								// Use proper order for row items in Masonry layout only.
								// Tiles layout may not work as expected with this option.
								horizontalOrder:
									self.options.masonryHorizontalOrder ===
									'true',
						  }
						: {},
				transitionDuration: '0.3s',
				// We don't use stagger anymore because it is not
				// working properly in a large galleries.
				// When screen resized, latest items transition is too big and it looks ugly.
				// stagger: '0.03s',
				percentPosition: true,
				originLeft: ! isRtl,

				// See `initEvents.vpf` event why we need this option disabled.
				resize: false,
			};

			self.emitEvent( 'beforeInitIsotope', [ initOptions ] );

			self.$items_wrap.isotope( initOptions );

			self.emitEvent( 'initIsotope', [ initOptions ] );
		}
	};

	/**
	 * Destroy Isotope
	 */
	VP.prototype.destroyIsotope = function () {
		const self = this;
		const isotope = self.$items_wrap.data( 'isotope' );

		if ( isotope ) {
			self.$items_wrap.isotope( 'destroy' );

			self.emitEvent( 'destroyIsotope' );
		}
	};
} );

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

	const isotope = self.$items_wrap.data( 'isotope' );

	if ( ! isotope ) {
		return;
	}

	if ( removeExisting ) {
		const $existing = self.$items_wrap.find( '.vp-portfolio__item-wrap' );
		self.$items_wrap.isotope( 'remove', $existing );

		// we need to prepend items when remove existing just because Tiles layout have troubles with appending and removing items
		self.$items_wrap.prepend( $items ).isotope( 'prepended', $items );
	} else {
		self.$items_wrap.append( $items ).isotope( 'appended', $items );
	}

	// Idk why, but with timeout isotope recalculate all items fine.
	// if we run only re-layout inside the timeout, there will be visible image blinking.
	// So, we need to make these 2 calls.
	self.initIsotope( 'layout' );
	setTimeout( () => {
		self.initIsotope( 'layout' );
	}, 0 );
} );

// Remove Items.
$doc.on( 'removeItems.vpf', ( event, self, $items ) => {
	if ( event.namespace !== 'vpf' ) {
		return;
	}

	const isotope = self.$items_wrap.data( 'isotope' );

	if ( ! isotope ) {
		return;
	}

	self.$items_wrap.isotope( 'remove', $items );
} );

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

	self.initIsotope();
} );

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

	// sometimes on iOs images failed to calculate positions, so we need this imagesLoaded event.
	// related issue: https://github.com/nk-crew/visual-portfolio/issues/55
	self.initIsotope( 'layout' );
} );

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

	self.destroyIsotope();
} );

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

	// We need to resize isotope manually, since the native relayout
	// is not working properly, when container size is not changed
	// but items sizes are changed in CSS. For some reason Isotope don't relayout it.
	if (
		self.$items_wrap.isotope &&
		SUPPORTED_LAYOUTS.includes( self.options.layout )
	) {
		const evp = `.vpf-uid-${ self.uid }`;

		$wnd.on(
			`resize${ evp }`,
			throttle(
				100,
				rafSchd( () => {
					self.initIsotope( 'layout' );
				} )
			)
		);
	}
} );

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

	if ( SUPPORTED_LAYOUTS.includes( self.options.layout ) ) {
		const evp = `.vpf-uid-${ self.uid }`;

		$wnd.off( `resize${ evp }` );
	}
} );

// WPBakery Page Builder fullwidth row fix.
$doc.on(
	'vc-full-width-row',
	debounce(
		150,
		rafSchd( ( event, el ) => {
			$( el )
				.find( '.vp-portfolio' )
				.each( function () {
					if ( ! this.vpf || ! this.vpf.initIsotope ) {
						return;
					}

					const isotope = this.vpf.$items_wrap.data( 'isotope' );

					if ( isotope ) {
						this.vpf.initIsotope( 'layout' );
					}
				} );
		} )
	)
);
