import { useWheel, usePinch } from '@use-gesture/react'
import { useDominoStoreInstance } from './domino-hooks'

const isMac =
  typeof navigator !== 'undefined' &&
  /Mac|iPhone|iPod|iPad/.test(navigator.userAgent)

export function useGestures(
  containerRef: React.RefObject<HTMLElement | null>,
  options: {
    minScale?: number
    maxScale?: number
  } = {},
) {
  const { minScale = 0.1, maxScale = 20 } = options
  const store = useDominoStoreInstance()
  const { moveViewport, zoomViewport, setViewport } = store.getState()

  // 更新 DOM 叠加层的状态类名（用于鼠标样式和业务联动）
  const updateDOMOverlay = (type: 'panning' | 'zooming' | 'none') => {
    const container = containerRef.current
    if (!container) return
    container.classList.toggle('is-panning', type === 'panning')
    container.classList.toggle('is-zooming', type === 'zooming')
  }

  useWheel(
    ({ delta: [dx, dy], event, ctrlKey, active }) => {
      // 冲突检测：如果滚轮发生在可滚动 UI 内部，不移动画布
      if (!ctrlKey) {
        const target = event.target as HTMLElement
        const scrollable = target?.closest(
          '.overflow-y-auto, .overflow-y-scroll, .overflow-auto, [data-radix-scroll-area-viewport], .scrollbar-container',
        )
        if (scrollable && scrollable.scrollHeight > scrollable.clientHeight) {
          return
        }
      }

      if (active) {
        updateDOMOverlay(ctrlKey ? 'zooming' : 'panning')
      } else {
        updateDOMOverlay('none')
      }

      if (ctrlKey) {
        event.preventDefault()
        const container = containerRef.current
        if (!container) return
        const rect = container.getBoundingClientRect()
        const cx = (event as WheelEvent).clientX - rect.left
        const cy = (event as WheelEvent).clientY - rect.top

        const multiplier = Math.min(
          1.25,
          Math.max(0.8, isMac ? 0.99 ** dy : 0.999 ** dy),
        )
        zoomViewport(multiplier, cx, cy, minScale, maxScale)
        return
      }

      event.preventDefault()
      moveViewport(-dx, -dy)
    },
    {
      target: containerRef,
      eventOptions: { passive: false },
    },
  )

  usePinch(
    ({ origin: [ox, oy], first, movement: [ms], memo, active }) => {
      if (active) {
        updateDOMOverlay('zooming')
      } else {
        updateDOMOverlay('none')
      }

      const container = containerRef.current
      if (!container) return

      if (first) {
        const { viewport } = store.getState()
        const rect = container.getBoundingClientRect()
        const cx = ox - rect.left
        const cy = oy - rect.top
        return {
          startScale: viewport.scale,
          anchorWx: (cx - viewport.x) / viewport.scale,
          anchorWy: (cy - viewport.y) / viewport.scale,
          cx,
          cy,
        }
      }

      const { cx, cy } = memo
      const sensitivity = 1.5
      const adjustedMs = 1 + (ms - 1) * sensitivity
      const targetScale = memo.startScale * adjustedMs
      const newScale = Math.max(minScale, Math.min(maxScale, targetScale))

      setViewport({
        x: cx - memo.anchorWx * newScale,
        y: cy - memo.anchorWy * newScale,
        scale: newScale,
      })

      return memo
    },
    {
      target: containerRef,
      eventOptions: { passive: false },
    },
  )
}
