import { computed, onMounted, onUnmounted, ref, type CSSProperties } from 'vue'

const FAB_SIZE = 56
const EDGE = 8
const BOTTOM_RESERVED = 64
const DRAG_THRESHOLD = 6

type Position = { x: number; y: number }

function clampPosition(x: number, y: number): Position {
  const maxX = Math.max(EDGE, window.innerWidth - FAB_SIZE - EDGE)
  const maxY = Math.max(EDGE, window.innerHeight - FAB_SIZE - BOTTOM_RESERVED - EDGE)
  return {
    x: Math.min(maxX, Math.max(EDGE, x)),
    y: Math.min(maxY, Math.max(EDGE, y)),
  }
}

export const FAB_POSITION_KEYS = ['wordloop-fab-train', 'wordloop-fab-translate'] as const

/** 登录/退出时清除，悬浮按钮恢复默认位置 */
export function clearFabPositions() {
  for (const key of FAB_POSITION_KEYS) {
    try {
      sessionStorage.removeItem(key)
      localStorage.removeItem(key)
    } catch {
      /* ignore */
    }
  }
}

function loadPosition(key: string): Position | null {
  try {
    const raw = sessionStorage.getItem(key)
    if (!raw) return null
    const parsed = JSON.parse(raw) as Position
    if (typeof parsed.x === 'number' && typeof parsed.y === 'number') return parsed
  } catch {
    /* ignore */
  }
  return null
}

function savePosition(key: string, pos: Position) {
  try {
    sessionStorage.setItem(key, JSON.stringify(pos))
  } catch {
    /* ignore */
  }
}

export function useDraggableFab(storageKey: string, getDefault: () => Position) {
  const x = ref(0)
  const y = ref(0)
  const dragging = ref(false)
  const dragMoved = ref(false)

  function applyPosition(pos: Position) {
    const clamped = clampPosition(pos.x, pos.y)
    x.value = clamped.x
    y.value = clamped.y
  }

  function init() {
    const saved = loadPosition(storageKey)
    applyPosition(saved ?? getDefault())
  }

  function onResize() {
    applyPosition({ x: x.value, y: y.value })
  }

  onMounted(() => {
    init()
    window.addEventListener('resize', onResize)
  })

  onUnmounted(() => {
    window.removeEventListener('resize', onResize)
  })

  const wrapStyle = computed<CSSProperties>(() => ({
    left: `${x.value}px`,
    top: `${y.value}px`,
    right: 'auto',
    bottom: 'auto',
    transform: 'none',
  }))

  function onFabPointerDown(e: PointerEvent) {
    if (e.button !== 0) return
    const el = e.currentTarget as HTMLElement
    el.setPointerCapture(e.pointerId)

    const startX = e.clientX
    const startY = e.clientY
    const originX = x.value
    const originY = y.value
    dragMoved.value = false

    const onMove = (ev: PointerEvent) => {
      const dx = ev.clientX - startX
      const dy = ev.clientY - startY
      if (!dragMoved.value && Math.hypot(dx, dy) < DRAG_THRESHOLD) return
      dragMoved.value = true
      dragging.value = true
      applyPosition({ x: originX + dx, y: originY + dy })
    }

    const onUp = () => {
      el.releasePointerCapture(e.pointerId)
      el.removeEventListener('pointermove', onMove)
      el.removeEventListener('pointerup', onUp)
      el.removeEventListener('pointercancel', onUp)
      if (dragMoved.value) {
        savePosition(storageKey, { x: x.value, y: y.value })
      }
      dragging.value = false
    }

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

  function consumeDragClick(): boolean {
    if (dragMoved.value) {
      dragMoved.value = false
      return true
    }
    return false
  }

  return { wrapStyle, dragging, onFabPointerDown, consumeDragClick }
}
