'use client'

import * as React from 'react'
import {
  SvgTaillessLineArrowDown1,
  SvgTaillessLineArrowUp1,
} from '@chainlink/blocks-icons'
import { cn } from '../../utils'

/** Tolerance (px) for scroll boundary detection. Use a small value so arrows show/hide precisely when content uses exact row heights (e.g. dropdownHeights). */
const SCROLL_ARROW_TOLERANCE = 1

function useScrollArrows({
  enabled = true,
  /** When set (e.g. combobox), keyboard/pointer check uses this ref instead of containerRef. Use a ref that wraps the whole focus scope (e.g. header + list) so input focus still counts. */
  focusScopeRef,
}: {
  enabled?: boolean
  focusScopeRef?: React.RefObject<HTMLElement | null>
} = {}) {
  const scrollRef = React.useRef<HTMLElement | null>(null)
  const containerRef = React.useRef<HTMLElement | null>(null)
  const scrollIntervalRef = React.useRef<ReturnType<typeof setInterval> | null>(
    null,
  )
  const [showScrollDown, setShowScrollDown] = React.useState(false)
  const [showScrollUp, setShowScrollUp] = React.useState(false)
  const [keyboardMode, setKeyboardMode] = React.useState(false)

  const checkScroll = React.useCallback(() => {
    const el = scrollRef.current
    if (!el) return
    const { scrollTop, clientHeight, scrollHeight } = el
    setShowScrollDown(
      scrollTop + clientHeight < scrollHeight - SCROLL_ARROW_TOLERANCE,
    )
    setShowScrollUp(scrollTop > SCROLL_ARROW_TOLERANCE)
  }, [])

  React.useEffect(() => {
    if (!enabled) return
    const scopeRef = focusScopeRef ?? containerRef
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return
      const container = scopeRef.current
      if (container && container.contains(document.activeElement)) {
        setKeyboardMode(true)
      }
    }
    const onPointerDown = (e: PointerEvent) => {
      const container = scopeRef.current
      if (container && container.contains(e.target as Node)) {
        setKeyboardMode(false)
      }
    }
    document.addEventListener('keydown', onKeyDown, true)
    document.addEventListener('pointerdown', onPointerDown)
    return () => {
      document.removeEventListener('keydown', onKeyDown, true)
      document.removeEventListener('pointerdown', onPointerDown)
    }
  }, [enabled, focusScopeRef])

  const stopAutoScroll = React.useCallback(() => {
    if (scrollIntervalRef.current) {
      clearInterval(scrollIntervalRef.current)
      scrollIntervalRef.current = null
    }
  }, [])

  const startAutoScroll = React.useCallback(
    (direction: 'up' | 'down') => {
      stopAutoScroll()
      scrollIntervalRef.current = setInterval(() => {
        const el = scrollRef.current
        if (!el) return
        const atBoundary =
          direction === 'down'
            ? el.scrollTop + el.clientHeight >=
              el.scrollHeight - SCROLL_ARROW_TOLERANCE
            : el.scrollTop <= SCROLL_ARROW_TOLERANCE
        if (atBoundary) {
          stopAutoScroll()
          checkScroll()
          return
        }
        el.scrollTop += direction === 'down' ? 4 : -4
        checkScroll()
      }, 16)
    },
    [checkScroll, stopAutoScroll],
  )

  const scrollToStart = React.useCallback(() => {
    stopAutoScroll()
    scrollRef.current?.scrollTo({ top: 0, behavior: 'smooth' })
  }, [stopAutoScroll])

  const scrollToEnd = React.useCallback(() => {
    stopAutoScroll()
    scrollRef.current?.scrollTo({
      top: scrollRef.current.scrollHeight,
      behavior: 'smooth',
    })
  }, [stopAutoScroll])

  React.useEffect(() => {
    if (!enabled || !scrollRef.current) return
    const ro = new ResizeObserver(() => checkScroll())
    ro.observe(scrollRef.current)
    checkScroll()
    return () => {
      ro.disconnect()
    }
  }, [enabled, checkScroll])

  React.useEffect(() => {
    if (enabled) {
      requestAnimationFrame(() => checkScroll())
      const timer = setTimeout(() => checkScroll(), 150)
      return () => clearTimeout(timer)
    }
    stopAutoScroll()
    return undefined
  }, [enabled, checkScroll, stopAutoScroll])

  React.useEffect(() => {
    return () => stopAutoScroll()
  }, [stopAutoScroll])

  return {
    scrollRef,
    containerRef,
    showScrollUp: showScrollUp && !keyboardMode,
    showScrollDown: showScrollDown && !keyboardMode,
    handleScroll: checkScroll,
    startAutoScroll,
    stopAutoScroll,
    scrollToStart,
    scrollToEnd,
  }
}

interface ScrollArrowProps {
  onHoverStart: () => void
  onHoverEnd: () => void
  onJump: () => void
  className?: string
}

function ScrollArrowUp({
  onHoverStart,
  onHoverEnd,
  onJump,
  className,
}: ScrollArrowProps) {
  return (
    <div
      data-scroll-hint="up"
      role="presentation"
      tabIndex={-1}
      aria-hidden
      onMouseEnter={onHoverStart}
      onMouseLeave={onHoverEnd}
      onClick={onJump}
      className={cn(
        'pointer-events-auto absolute inset-x-0 top-0 z-10 flex h-6 cursor-pointer items-center justify-center bg-background',
        className,
      )}
    >
      <SvgTaillessLineArrowUp1
        height={10}
        width={10}
        className="h-2.5 w-2.5 text-input-muted-foreground"
      />
    </div>
  )
}

function ScrollArrowDown({
  onHoverStart,
  onHoverEnd,
  onJump,
  className,
}: ScrollArrowProps) {
  return (
    <div
      data-scroll-hint="down"
      role="presentation"
      tabIndex={-1}
      aria-hidden
      onMouseEnter={onHoverStart}
      onMouseLeave={onHoverEnd}
      onClick={onJump}
      className={cn(
        'pointer-events-auto absolute inset-x-0 bottom-0 z-10 flex h-6 cursor-pointer items-center justify-center bg-background',
        className,
      )}
    >
      <SvgTaillessLineArrowDown1
        height={10}
        width={10}
        className="h-2.5 w-2.5 text-input-muted-foreground"
      />
    </div>
  )
}

export { useScrollArrows, ScrollArrowUp, ScrollArrowDown }
