import type { App, Directive, DirectiveBinding, Plugin } from 'vue'

import type { LightboxItem } from './lightbox.types'
import { IMAGE_FORMATS_REGEXP, pathKeyToURL, VIDEO_FORMATS_REGEXP } from '@bagelink/vue'
import { createApp } from 'vue'
import Lightbox from './Lightbox.vue'

type OpenFunction = (item: LightboxItem, groupItems?: LightboxItem[]) => void
const groups: { [key: string]: LightboxItem[] } = {}

let clickHandler: ((e: MouseEvent) => any) = (_e: MouseEvent) => void 0

const lightboxDirective: Directive = {
	mounted(el: HTMLElement, binding) {
		const item = bindingToItem(binding, el)
		groupHandler(item)
		clickHandler = (e: MouseEvent) => { openClickHandler(e, el, binding) }
		el.addEventListener('click', clickHandler)
	},
	updated(el: HTMLElement, binding) {
		const item = bindingToItem(binding, el)
		groupHandler(item)

		el.removeEventListener('click', clickHandler)
		clickHandler = (e: MouseEvent) => { openClickHandler(e, el, binding) }
		el.addEventListener('click', clickHandler)
	},
	unmounted(el: HTMLElement) {
		el.removeEventListener('click', clickHandler)
	},
	getSSRProps() {
		return {}
	},
}

function groupHandler(item: LightboxItem) {
	if (item.group) {
		if (!groups[item.group]) { groups[item.group] = [] }
		const currentIndex = groups[item.group].findIndex(i => i.src === item.src)
		if (currentIndex === -1) { groups[item.group].push(item) }
	}
}

function openClickHandler(e: MouseEvent, el: HTMLElement, binding: DirectiveBinding) {
	e.stopPropagation()
	const item = bindingToItem(binding, el)
	const lightboxInstance = getLightboxInstance()
	if (!lightboxInstance || !lightboxInstance.open) { return }
	const open = lightboxInstance.open as OpenFunction
	const group = item && item.group ? groups[item.group] : undefined
	open(item, group)
}

function bindingToItem(binding: DirectiveBinding, el: HTMLElement): LightboxItem {
	let { group, src, type, name, thumbnail, enableZoom, openFile, download, pathKey } = binding.value || {}
	src = pathKeyToURL(src || pathKey) || binding.value || el.getAttribute('src') || ''
	type = type || determineFileType(src)
	name = name || urlToName(src) || el.getAttribute('alt') || ''
	return { src, type, name, thumbnail, group, enableZoom,	openFile, download }
}

const youtubeRegex = /youtube\.com|youtu\.be/
const vimeoRegex = /vimeo\.com/

function urlToName(url: string): string {
	if (!url || typeof url !== 'string') { return '' }
	const name = url.split('/').pop() || ''
	return name.replace(/\.[^/.]+$/, '')
}

function determineFileType(url: any): string {
	if (typeof url !== 'string' || !url) { return 'unknown' }
	const extension = (url.split('.').pop() || '').toLowerCase()
	const altExtension = url.split('?')[0].split('.').pop()?.toLowerCase() || ''
	if (IMAGE_FORMATS_REGEXP.test(extension) || IMAGE_FORMATS_REGEXP.test(altExtension)) { return 'image' }
	if (VIDEO_FORMATS_REGEXP.test(extension) || youtubeRegex.test(url) || vimeoRegex.test(url)) { return 'video' }
	if (['pdf'].includes(extension)) { return 'pdf' }
	return extension ?? 'unknown'
}

let lightboxInstance: InstanceType<typeof Lightbox> | undefined

function getLightboxInstance(): InstanceType<typeof Lightbox> | undefined {
	if (typeof document === 'undefined') { return undefined }
	if (!lightboxInstance) {
		const lightboxEl = document.createElement('div')
		document.body.prepend(lightboxEl)
		const app = createApp(Lightbox)
		lightboxInstance = app.mount(lightboxEl) as InstanceType<typeof Lightbox>
	}
	return lightboxInstance
}

const lightboxPlugin: Plugin = {
	install(app: App) {
		app.directive('lightbox', lightboxDirective)
	},
}

export default lightboxPlugin
