"use client"

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

export const PULL_HOLD_HEIGHT = 48
export const PULL_REFRESH_THRESHOLD = 56
export const PULL_REFRESH_MAX = 112
export const PULL_SNAP_BACK_TRANSITION =
  "transform 0.24s cubic-bezier(0.32, 0.72, 0, 1)"
export const REFRESH_SPIN_CLASS = "animate-[spin_0.55s_linear_infinite]"
export const PULL_ICON_FADE_MS = 120
export const PULL_SPINNER_REVEAL_OFFSET = 26

export function computePullOffset(delta: number): number {
  if (delta <= 0) return 0
  const damped = delta * 0.48
  const capped = Math.min(PULL_REFRESH_MAX, damped)
  const ratio = capped / PULL_REFRESH_MAX
  return capped * (1 - ratio * 0.12)
}

export function computeSpinnerRevealProgress(y: number): number {
  if (y <= PULL_SPINNER_REVEAL_OFFSET) return 0
  const range = Math.max(1, PULL_REFRESH_THRESHOLD - PULL_SPINNER_REVEAL_OFFSET)
  return Math.min(1, ((y - PULL_SPINNER_REVEAL_OFFSET) / range) * 1.35)
}

export function useMailListPullRefresh(opts: {
  enabled: boolean
  isViewMode: boolean
  onRefresh: () => void | Promise<void>
}) {
  const { enabled, isViewMode, onRefresh } = opts
  const [isRefreshing, setIsRefreshing] = useState(false)
  const pullYRef = useRef(0)
  const pullActiveRef = useRef(false)
  const pullContentRef = useRef<HTMLDivElement>(null)
  const pullIconRef = useRef<SVGSVGElement | null>(null)
  const listViewportRef = useRef<HTMLDivElement>(null)

  const applyPullVisual = useCallback((y: number, animate: boolean) => {
    const el = pullContentRef.current
    const icon = pullIconRef.current
    if (!el) return
    const transition = animate ? PULL_SNAP_BACK_TRANSITION : "none"
    el.style.transition = transition
    el.style.transform = y > 0 ? `translateY(${y}px)` : ""
    if (icon) {
      const progress = computeSpinnerRevealProgress(y)
      icon.style.opacity = String(progress)
      icon.style.transform = `rotate(${progress * 360}deg)`
      icon.style.transition = animate
        ? `opacity ${PULL_ICON_FADE_MS}ms ease-out, transform ${PULL_ICON_FADE_MS}ms ease-out`
        : "none"
    }
  }, [])

  const resetPullVisual = useCallback(() => {
    pullYRef.current = 0
    applyPullVisual(0, true)
  }, [applyPullVisual])

  const releasePull = useCallback(async () => {
    const offset = pullYRef.current
    pullActiveRef.current = false
    if (offset >= PULL_REFRESH_THRESHOLD) {
      pullYRef.current = PULL_HOLD_HEIGHT
      applyPullVisual(PULL_HOLD_HEIGHT, false)
      setIsRefreshing(true)
      try {
        await onRefresh()
      } finally {
        setIsRefreshing(false)
        pullYRef.current = 0
        applyPullVisual(0, true)
      }
    } else {
      resetPullVisual()
    }
  }, [applyPullVisual, onRefresh, resetPullVisual])

  useEffect(() => {
    if (isViewMode || !enabled || isRefreshing) return
    const root = listViewportRef.current
    if (!root) return

    let startY = 0
    const onTouchStart = (e: TouchEvent) => {
      if (root.scrollTop > 0 || isRefreshing) return
      startY = e.touches[0]?.clientY ?? 0
      pullActiveRef.current = true
    }
    const onTouchMove = (e: TouchEvent) => {
      if (!pullActiveRef.current || isRefreshing) return
      const y = e.touches[0]?.clientY ?? 0
      const delta = y - startY
      if (delta <= 0) {
        pullYRef.current = 0
        applyPullVisual(0, false)
        return
      }
      if (root.scrollTop > 0) return
      e.preventDefault()
      const offset = computePullOffset(delta)
      pullYRef.current = offset
      applyPullVisual(offset, false)
    }
    const onTouchEnd = () => {
      if (!pullActiveRef.current) return
      void releasePull()
    }

    root.addEventListener("touchstart", onTouchStart, { passive: true })
    root.addEventListener("touchmove", onTouchMove, { passive: false })
    root.addEventListener("touchend", onTouchEnd)
    root.addEventListener("touchcancel", onTouchEnd)
    return () => {
      root.removeEventListener("touchstart", onTouchStart)
      root.removeEventListener("touchmove", onTouchMove)
      root.removeEventListener("touchend", onTouchEnd)
      root.removeEventListener("touchcancel", onTouchEnd)
    }
  }, [enabled, isRefreshing, isViewMode, applyPullVisual, releasePull])

  return {
    isRefreshing,
    setIsRefreshing,
    listViewportRef,
    pullContentRef,
    pullIconRef,
    resetPullVisual,
  }
}
