import $ from 'jquery'
import ctEvents from 'ct-events'
import { markImagesAsLoaded } from '../lazy-load-helpers'

let originalImageUpdate = null

const store = {}

function isTouchDevice() {
	try {
		document.createEvent('TouchEvent')
		return true
	} catch (e) {
		return false
	}
}

const cachedFetch = (url) =>
	store[url]
		? new Promise((resolve) => {
				resolve(store[url])
				store[url] = store[url].clone()
		  })
		: new Promise((resolve) =>
				fetch(url).then((response) => {
					resolve(response)
					store[url] = response.clone()
				})
		  )

const makeUrlFor = ({ variation, productId, isQuickView }) => {
	let url = new URL(ct_localizations.ajax_url)
	let params = new URLSearchParams(url.search.slice(1))

	params.append('action', 'blocksy_get_product_view_for_variation')
	params.append('variation_id', variation.variation_id)
	params.append('product_id', productId)
	params.append('is_quick_view', isQuickView)

	url.search = `?${params.toString()}`

	return url.toString()
}

const replaceFirstImage = ({ container, image }) => {
	const containersToReplace = []

	const selectorsToTry = [
		'.woocommerce-product-gallery > .ct-image-container',
		'.woocommerce-product-gallery .flexy-items > *:first-child > *',
		'.woocommerce-product-gallery .flexy-pills > ol > *:first-child > *',
	]

	selectorsToTry.map((selector) => {
		if (container.parentNode.querySelector(selector)) {
			containersToReplace.push(
				container.parentNode.querySelector(selector)
			)
		}
	})

	containersToReplace.map((imgContainer) => {
		if (imgContainer.href) {
			imgContainer.href = image.full_src
		}

		if (imgContainer.dataset.height) {
			imgContainer.dataset.height = image.full_src_h
		}

		if (imgContainer.dataset.width) {
			imgContainer.dataset.width = image.full_src_w
		}

		;[...imgContainer.querySelectorAll('img')].map((img) => {
			if (img.matches('.zoomImg')) {
				return
			}

			if (img.getAttribute('width')) {
				img.width = image.width
			}

			if (img.getAttribute('height')) {
				img.height = image.height
			}

			img.src = image.src

			if (img.dataset.ctLazy) {
				img.dataset.ctLazy = image.src
			}

			if (img.dataset.ctLazySet) {
				img.dataset.ctLazySet = image.srcset
			}

			if (img.sizes) {
				img.sizes = image.sizes
			}

			if (img.srcset) {
				img.srcset = image.srcset
			}
		})

		if (imgContainer.querySelector('img.zoomImg')) {
			if ($.fn.zoom) {
				if (
					(window.wp &&
						wp.customize &&
						wp.customize('has_product_single_zoom') &&
						wp.customize('has_product_single_zoom')() === 'yes') ||
					!window.wp ||
					!wp.customize
				) {
					const rect = imgContainer.getBoundingClientRect()

					$(imgContainer).zoom({
						url: imgContainer.href,
						touch: false,
						duration: 50,

						...(rect.width >
							parseFloat(imgContainer.dataset.width) ||
						rect.height > parseFloat(imgContainer.dataset.height)
							? {
									magnify: 2,
							  }
							: {}),

						...(isTouchDevice()
							? {
									on: 'toggle',
							  }
							: {}),
					})
				}
			}
		}
	})
}

const performInPlaceUpdate = ({
	container,
	currentVariationObj,
	nextVariationObj,
}) => {
	const currentImage = currentVariationObj
		? { id: currentVariationObj.image_id, ...currentVariationObj.image }
		: nextVariationObj.blocksy_original_image

	const nextImage = nextVariationObj
		? { id: nextVariationObj.image_id, ...nextVariationObj.image }
		: currentVariationObj.blocksy_original_image

	if (parseFloat(nextImage.id) === parseFloat(currentImage.id)) {
		return
	}

	// Attempt slide to image

	if (container.querySelector(`.flexy-pills > *`)) {
		let maybePillImage =
			container.querySelector(
				`.flexy-items [srcset*="${nextImage.src}"]`
			) ||
			container.querySelector(
				`.flexy-items [data-ct-lazy-set*="${nextImage.src}"]`
			)

		if (maybePillImage) {
			let pillIndex = [
				...container.querySelector(`.flexy-items`).children,
			].indexOf(maybePillImage.closest('div'))

			const pill = container.querySelector(`.flexy-pills > *`).children[
				pillIndex
			]

			if (pill) {
				if (
					container
						.querySelector('[data-flexy]')
						.dataset.flexy.indexOf('no') > -1
				) {
					if (container.querySelector('[data-flexy]').forcedMount) {
						container.querySelector('[data-flexy]').forcedMount()
					}

					setTimeout(() => {
						if (nextVariationObj) {
							replaceFirstImage({
								container,
								image: nextVariationObj.blocksy_original_image,
							})
						}
						pill.click()
					}, 500)

					return
				} else {
					if (nextVariationObj) {
						replaceFirstImage({
							container,
							image: nextVariationObj.blocksy_original_image,
						})
					}

					pill.click()
					return
				}
			}
		}
	}

	// Replace 1st image

	replaceFirstImage({ container, image: nextImage })

	if (container.querySelector(`.flexy-pills > *`)) {
		const pill = container.querySelector(`.flexy-pills > *`).children[0]

		if (pill) {
			pill.click()
		}
	}
}

export const mount = (el) => {
	if (!$ || !$.fn || !$.fn.wc_variations_image_update) {
		return
	}

	originalImageUpdate = $.fn.wc_variations_image_update

	$.fn.wc_variations_image_update = function (variation) {
		const currentVariation = el
			.closest('.product')
			.querySelector('.woocommerce-product-gallery')

		let productContainer = currentVariation.closest('.type-product')

		let isQuickView = 'no'

		let productId = productContainer.id.replace('product-', '')

		if (!productId) {
			productId = currentVariation
				.closest('[class*="ct-quick-view"]')
				.querySelector('[data-product_id]').dataset.product_id

			if (productId) {
				isQuickView = 'yes'
			}
		}

		const allVariations = JSON.parse(el.dataset.product_variations)

		let nextVariationObj = false
		let currentVariationObj = false

		if (allVariations) {
			nextVariationObj = variation.variation_id
				? allVariations.find(
						({ variation_id }) =>
							parseInt(variation_id) ===
							parseInt(variation.variation_id)
				  )
				: false
			currentVariationObj = currentVariation.dataset.currentVariation
				? allVariations.find(
						({ variation_id }) =>
							parseInt(variation_id) ===
							parseInt(currentVariation.dataset.currentVariation)
				  )
				: false
		}

		if (
			!variation.variation_id &&
			!currentVariation.dataset.currentVariation
		) {
			return
		}

		if (
			parseInt(variation.variation_id) ===
			parseInt(currentVariation.dataset.currentVariation)
		) {
			return
		}

		if (variation.variation_id) {
			currentVariation.dataset.currentVariation = variation.variation_id
		} else {
			currentVariation.removeAttribute('data-current-variation')
		}

		const canDoInPlaceUpdate =
			allVariations &&
			[nextVariationObj, currentVariationObj].every((variation) => {
				if (!variation) {
					return true
				}

				return variation.blocksy_gallery_source === 'default'
			})

		if (canDoInPlaceUpdate) {
			performInPlaceUpdate({
				container: currentVariation,
				nextVariationObj,
				currentVariationObj,
			})
			return
		}

		const acceptHtml = (html) => {
			const div = document.createElement('div')
			div.innerHTML = html

			currentVariation.innerHTML = div.firstElementChild.innerHTML

			markImagesAsLoaded(currentVariation)

			currentVariation.hasLazyLoadClickHoverListener = false

			setTimeout(() => {
				ctEvents.trigger('blocksy:frontend:init')
				currentVariation.removeAttribute('data-state')
			})
		}

		if (variation.blocksy_gallery_html) {
			acceptHtml(variation.blocksy_gallery_html)
			return
		}

		currentVariation.removeAttribute('style')
		requestAnimationFrame(() => {
			currentVariation.dataset.state = 'loading'
		})

		let maybeLoadedVariation = allVariations
			? allVariations.find(
					(nestedVariation) =>
						store[
							makeUrlFor({
								variation: nestedVariation,
								productId,
								isQuickView,
							})
						] &&
						nestedVariation.image_id === variation.image_id &&
						variation.blocksy_gallery_source === 'default' &&
						nestedVariation.blocksy_gallery_source === 'default'
			  )
			: null

		cachedFetch(
			makeUrlFor({
				variation: maybeLoadedVariation || variation,
				productId,
				isQuickView,
			}),
			{
				method: 'POST',
			}
		)
			.then((response) => response.json())
			.then(({ success, data }) => {
				if (!success) {
					return
				}

				acceptHtml(data.html)
			})
	}
}
