"use client"

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

import {
  BALL_SIZE,
  HIDE_THRESHOLD,
  MARGIN,
  type Position,
  clampPosition,
  getDefaultPosition,
  savePosition,
  usePositionPersistence,
} from "./use-position-persistence"
import { useDragPosition } from "./use-drag-position"

/**
 * 计算吸附到最近边缘后的 X 坐标
 */
function snapToEdge(x: number): number {
  if (typeof window === "undefined") return x
  const w = window.innerWidth
  const centerX = x + BALL_SIZE / 2
  const distanceToLeft = centerX
  const distanceToRight = w - centerX
  return distanceToLeft < distanceToRight ? MARGIN : w - BALL_SIZE - MARGIN
}

/**
 * 计算半隐藏时的视觉偏移量
 */
function calculateHiddenOffset(
  position: Position,
  hidden: boolean,
  hovered: boolean,
  dragging: boolean
): number {
  if (!hidden || hovered || dragging) return 0
  return position.x <= MARGIN + 2
    ? -(BALL_SIZE * HIDE_THRESHOLD)
    : BALL_SIZE * HIDE_THRESHOLD
}

/**
 * 可拖拽悬浮球 Hook（360 悬浮球风格）
 *
 * 特性：
 * - 鼠标/触摸拖拽，松手后吸附到最近屏幕边缘
 * - 拖到边缘超过阈值时半隐藏（只露出一小部分）
 * - 单击（未发生拖动）触发 onClick
 * - 位置持久化到 localStorage
 * - 窗口 resize 时自动校正位置
 *
 * V3：拆分为 use-position-persistence + use-drag-position + 本 hook 组合
 */
export function useFloatingBall(onClick: () => void): {
  position: Position
  hidden: boolean
  dragging: boolean
  hovered: boolean
  hiddenOffset: number
  handlers: {
    onPointerDown: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerMove: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerUp: (e: React.PointerEvent<HTMLButtonElement>) => void
    onPointerCancel: () => void
    onMouseEnter: () => void
    onMouseLeave: () => void
  }
  show: () => void
  resetPosition: () => void
} {
  const { position, setPosition } = usePositionPersistence()
  const [hidden, setHidden] = useState(false)
  const [hovered, setHovered] = useState(false)
  // 拖拽释放后标记"刚隐藏"，阻止 mouseEnter 立即展开
  const justHiddenRef = useRef(false)

  const onClickRef = useRef(onClick)
  useEffect(() => {
    onClickRef.current = onClick
  }, [onClick])

  const handleDragStart = useCallback((): void => {
    setHidden(false)
  }, [])

  const handleRelease = useCallback(
    (moved: boolean): void => {
      // 未移动 → 视为点击
      if (!moved) {
        onClickRef.current()
        return
      }
      // 移动了 → 吸附到最近边缘
      const snappedX = snapToEdge(position.x)
      const finalPos = clampPosition({ x: snappedX, y: position.y })
      setPosition(finalPos)
      savePosition(finalPos)
      setHidden(true)
      // 标记刚隐藏，阻止后续 mouseEnter 立即展开
      justHiddenRef.current = true
      // 清除 hovered，确保 hiddenOffset 生效
      setHovered(false)
    },
    [position, setPosition]
  )

  const { dragging, handlers: dragHandlers } = useDragPosition(
    position,
    setPosition,
    { onDragStart: handleDragStart, onRelease: handleRelease }
  )

  const handleMouseEnter = useCallback((): void => {
    // 如果刚通过拖拽隐藏，不立即展开（需先离开再进入才展开）
    if (justHiddenRef.current) {
      justHiddenRef.current = false
      return
    }
    setHovered(true)
    if (hidden) setHidden(false)
  }, [hidden])

  const handleMouseLeave = useCallback((): void => {
    setHovered(false)
    // 离开后清除 justHidden 标记，下次进入可正常展开
    justHiddenRef.current = false
  }, [])

  const show = useCallback((): void => {
    justHiddenRef.current = false
    setHidden(false)
  }, [])

  const resetPosition = useCallback((): void => {
    justHiddenRef.current = false
    const fresh = getDefaultPosition()
    setPosition(fresh)
    savePosition(fresh)
    setHidden(false)
  }, [setPosition])

  const hiddenOffset = calculateHiddenOffset(position, hidden, hovered, dragging)

  return {
    position,
    hidden,
    dragging,
    hovered,
    hiddenOffset,
    handlers: {
      ...dragHandlers,
      onMouseEnter: handleMouseEnter,
      onMouseLeave: handleMouseLeave,
    },
    show,
    resetPosition,
  }
}
