import type { Directive } from 'vue'

export interface ResizeEvent {
	clientY: number
	deltaY: number
	initialHeight: number
}

export interface ResizeOptions {
	onStart?: (event: MouseEvent | TouchEvent) => void
	onResize?: (event: ResizeEvent) => void
	onEnd?: (event: ResizeEvent) => void
	minHeight?: number
	maxHeight?: number
	handle?: string
	gridSize?: number
	handleClass?: string
}

const RESIZE_KEY = Symbol('resize')

function initResize(el: HTMLElement, binding: { value?: ResizeOptions }) {
	const options = binding.value || {}
	let isResizing = false
	let startY = 0
	let startHeight = 0
	let handleElement: HTMLElement | null = null

	// Create or find the resize handle
	if (options.handle) {
		handleElement = el.querySelector(options.handle) as HTMLElement
		if (!handleElement) {
			// If handle not found, create it
			handleElement = document.createElement('div')
			handleElement.className = options.handle.replace('.', '') + (options.handleClass ? ` ${options.handleClass}` : '')
			handleElement.style.cssText = `
				position: absolute;
				bottom: 0;
				left: 0;
				right: 0;
				height: 6px;
				background: rgba(0, 0, 0, 0.1);
				cursor: ns-resize;
				transition: background 0.2s;
			`
			el.appendChild(handleElement)
		}
	} else {
		handleElement = el
	}

	// Add hover effect
	handleElement.addEventListener('mouseenter', () => {
		if (handleElement !== el) { // Only change background if it's a dedicated handle
			handleElement!.style.background = 'rgba(0, 0, 0, 0.2)'
		}
	})
	handleElement.addEventListener('mouseleave', () => {
		if (handleElement !== el && !isResizing) { // Only change background if it's a dedicated handle and not resizing
			handleElement!.style.background = 'rgba(0, 0, 0, 0.1)'
		}
	})

	handleElement.style.cursor = 'ns-resize'
	handleElement.style.userSelect = 'none'

	function createResizeEvent(clientY: number): ResizeEvent {
		return {
			clientY,
			deltaY: clientY - startY,
			initialHeight: startHeight
		}
	}

	function applyGridSnapping(height: number): number {
		if (!options.gridSize) { return height }
		return Math.round(height / options.gridSize) * options.gridSize
	}

	function handleMove(e: MouseEvent | TouchEvent) {
		if (!isResizing) { return }
		e.preventDefault()

		const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY
		const event = createResizeEvent(clientY)
		let newHeight = startHeight + event.deltaY

		// Apply min/max constraints
		if (options.minHeight !== undefined) {
			newHeight = Math.max(newHeight, options.minHeight)
		}
		if (options.maxHeight !== undefined) {
			newHeight = Math.min(newHeight, options.maxHeight)
		}

		// Apply grid snapping if enabled
		newHeight = applyGridSnapping(newHeight)

		el.style.height = `${newHeight}px`

		if (options.onResize) {
			options.onResize(event)
		}

		// Update handle appearance during resize
		if (handleElement !== el) {
			handleElement!.style.background = 'rgba(0, 0, 0, 0.3)'
		}
	}

	function handleEnd(e: MouseEvent | TouchEvent) {
		if (!isResizing) { return }

		const clientY = 'touches' in e ? e.changedTouches[0].clientY : e.clientY
		const event = createResizeEvent(clientY)

		isResizing = false
		document.body.style.cursor = ''
		document.body.style.userSelect = ''

		// Reset handle appearance
		if (handleElement !== el) {
			handleElement!.style.background = 'rgba(0, 0, 0, 0.1)'
		}

		if (options.onEnd) {
			options.onEnd(event)
		}

		document.removeEventListener('mousemove', handleMove)
		document.removeEventListener('mouseup', handleEnd)
		document.removeEventListener('touchmove', handleMove)
		document.removeEventListener('touchend', handleEnd)
		document.removeEventListener('touchcancel', handleEnd)
	}

	function handleStart(e: MouseEvent | TouchEvent) {
		// Only handle left mouse button for mouse events
		if (e instanceof MouseEvent && e.button !== 0) { return }

		e.preventDefault()
		isResizing = true

		startY = 'touches' in e ? e.touches[0].clientY : e.clientY
		startHeight = el.offsetHeight

		if (options.onStart) {
			options.onStart(e)
		}

		document.body.style.cursor = 'ns-resize'
		document.body.style.userSelect = 'none'

		document.addEventListener('mousemove', handleMove, { passive: false })
		document.addEventListener('mouseup', handleEnd)
		document.addEventListener('touchmove', handleMove, { passive: false })
		document.addEventListener('touchend', handleEnd)
		document.addEventListener('touchcancel', handleEnd)
	}

	// Add initial event listeners
	handleElement.addEventListener('mousedown', handleStart)
	handleElement.addEventListener('touchstart', handleStart, { passive: false })

	// Store cleanup function
	;(el as any)[RESIZE_KEY] = () => {
		if (handleElement !== el) {
			el.removeChild(handleElement!)
		}
		handleElement.removeEventListener('mousedown', handleStart)
		handleElement.removeEventListener('touchstart', handleStart)
		handleElement.removeEventListener('mouseenter', handleStart)
		handleElement.removeEventListener('mouseleave', handleStart)
		document.removeEventListener('mousemove', handleMove)
		document.removeEventListener('mouseup', handleEnd)
		document.removeEventListener('touchmove', handleMove)
		document.removeEventListener('touchend', handleEnd)
		document.removeEventListener('touchcancel', handleEnd)
	}
}

export const vResize: Directive<HTMLElement, ResizeOptions> = {
	mounted(el, binding) {
		initResize(el, binding)
	},

	unmounted(el) {
		const cleanup = (el as any)[RESIZE_KEY]
		if (typeof cleanup === 'function') {
			cleanup()
			delete (el as any)[RESIZE_KEY]
		}
	},

	updated(el, binding) {
		if (binding.value !== binding.oldValue) {
			const cleanup = (el as any)[RESIZE_KEY]
			if (typeof cleanup === 'function') {
				cleanup()
				delete (el as any)[RESIZE_KEY]
			}
			initResize(el, binding)
		}
	},
	getSSRProps() {
		return {}
	},
}
