import { ref } from 'vue'

const LONG_PRESS_MS = 450
const PRE_DRAG_MOVE_PX = 10

export interface QuickDragTile {
  key: string
  label: string
  icon: unknown
  primary?: boolean
}

export function useQuickEntryDragSwap(
  swapKeys: (keyA: string, keyB: string) => Promise<void>
) {
  const dragKey = ref<string | null>(null)
  const hoverTargetKey = ref<string | null>(null)
  const ghostPos = ref({ x: 0, y: 0 })

  let pressTimer: ReturnType<typeof setTimeout> | null = null
  let suppressClick = false
  let active = false

  function clearPressTimer() {
    if (pressTimer) {
      clearTimeout(pressTimer)
      pressTimer = null
    }
  }

  function findTargetKey(clientX: number, clientY: number, sourceKey: string): string | null {
    const el = document.elementFromPoint(clientX, clientY)
    const tile = el?.closest('[data-quick-key]') as HTMLElement | null
    const key = tile?.dataset.quickKey
    if (!key || key === 'add' || key === sourceKey) return null
    return key
  }

  function onPointerDown(item: QuickDragTile, e: PointerEvent) {
    if (item.key === 'add' || e.button !== 0) return

    const target = e.currentTarget as HTMLElement
    const startX = e.clientX
    const startY = e.clientY
    let dragging = false

    clearPressTimer()
    active = true

    const cleanup = () => {
      clearPressTimer()
      active = false
      dragging = false
      window.removeEventListener('pointermove', onMove)
      window.removeEventListener('pointerup', onUp)
      window.removeEventListener('pointercancel', onUp)
    }

    const onMove = (ev: PointerEvent) => {
      if (!dragging) {
        const dx = ev.clientX - startX
        const dy = ev.clientY - startY
        if (dx * dx + dy * dy > PRE_DRAG_MOVE_PX * PRE_DRAG_MOVE_PX) {
          clearPressTimer()
        }
        return
      }

      ghostPos.value = { x: ev.clientX, y: ev.clientY }
      hoverTargetKey.value = findTargetKey(ev.clientX, ev.clientY, item.key)
    }

    const onUp = async (ev: PointerEvent) => {
      clearPressTimer()

      if (dragging) {
        suppressClick = true
        const from = item.key
        const to = hoverTargetKey.value ?? findTargetKey(ev.clientX, ev.clientY, from)
        dragKey.value = null
        hoverTargetKey.value = null
        if (to) {
          try {
            await swapKeys(from, to)
          } catch {
            /* persist failed */
          }
        }
      }

      cleanup()
    }

    pressTimer = setTimeout(() => {
      pressTimer = null
      dragging = true
      suppressClick = false
      dragKey.value = item.key
      ghostPos.value = { x: e.clientX, y: e.clientY }
      hoverTargetKey.value = null
      try {
        target.setPointerCapture(e.pointerId)
      } catch {
        /* ignore */
      }
    }, LONG_PRESS_MS)

    window.addEventListener('pointermove', onMove)
    window.addEventListener('pointerup', onUp)
    window.addEventListener('pointercancel', onUp)
  }

  function shouldSuppressClick(): boolean {
    if (!suppressClick) return false
    suppressClick = false
    return true
  }

  return {
    dragKey,
    hoverTargetKey,
    ghostPos,
    onPointerDown,
    shouldSuppressClick
  }
}
