"use client"

import { useCallback, useEffect, useRef, useState } from "react"

import type { Position } from "./use-position-persistence"
import { clampPosition } from "./use-position-persistence"

type DragState = {
  active: boolean
  moved: boolean
  startX: number
  startY: number
  originX: number
  originY: number
  pointerId: number
}

type DragCallbacks = {
  /** 拖拽开始时触发（pointer down 后） */
  onDragStart: () => void
  /** 拖拽释放时触发，moved 表示是否发生了实际移动 */
  onRelease: (moved: boolean) => void
}

/**
 * 拖拽位置 Hook
 *
 * 处理 pointer 事件，跟踪拖拽状态与位置变化。
 * 不处理边缘吸附、持久化等业务逻辑，通过回调委托给调用方。
 */
export function useDragPosition(
  position: Position,
  setPosition: React.Dispatch<React.SetStateAction<Position>>,
  callbacks: DragCallbacks
): {
  dragging: boolean
  handlers: {
    onPointerDown: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerMove: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerUp: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerCancel: () => void
  }
} {
  const [dragging, setDragging] = useState(false)
  const dragStateRef = useRef<DragState>({
    active: false,
    moved: false,
    startX: 0,
    startY: 0,
    originX: 0,
    originY: 0,
    pointerId: -1,
  })
  const callbacksRef = useRef(callbacks)
  useEffect(() => {
    callbacksRef.current = callbacks
  }, [callbacks])

  const onPointerDown = useCallback(
    (e: React.PointerEvent<HTMLButtonElement>): void => {
      // 仅主键响应拖拽
      if (e.button !== 0 && e.pointerType === "mouse") return
      const s = dragStateRef.current
      s.active = true
      s.moved = false
      s.startX = e.clientX
      s.startY = e.clientY
      s.originX = position.x
      s.originY = position.y
      s.pointerId = e.pointerId
      try {
        e.currentTarget.setPointerCapture(e.pointerId)
      } catch {
        // ignore
      }
      setDragging(true)
      callbacksRef.current.onDragStart()
    },
    [position]
  )

  const onPointerMove = useCallback(
    (e: React.PointerEvent<HTMLButtonElement>): void => {
      const s = dragStateRef.current
      if (!s.active || e.pointerId !== s.pointerId) return
      const dx = e.clientX - s.startX
      const dy = e.clientY - s.startY
      // 阈值过滤微抖动
      if (!s.moved && Math.abs(dx) + Math.abs(dy) < 4) return
      s.moved = true
      const next = clampPosition({
        x: s.originX + dx,
        y: s.originY + dy,
      })
      setPosition(next)
    },
    [setPosition]
  )

  const onPointerUp = useCallback(
    (e: React.PointerEvent<HTMLButtonElement>): void => {
      const s = dragStateRef.current
      if (!s.active || e.pointerId !== s.pointerId) return
      s.active = false
      setDragging(false)
      try {
        e.currentTarget.releasePointerCapture(e.pointerId)
      } catch {
        // ignore
      }
      callbacksRef.current.onRelease(s.moved)
    },
    []
  )

  const onPointerCancel = useCallback((): void => {
    dragStateRef.current.active = false
    setDragging(false)
  }, [])

  return {
    dragging,
    handlers: {
      onPointerDown,
      onPointerMove,
      onPointerUp,
      onPointerCancel,
    },
  }
}
