import { Button, Colors } from '@blueprintjs/core'
import { Dot } from '@blueprintjs/icons'
import { useCallback, useEffect, useRef, useState, type FC } from 'react'

const TOLERANCE = 20

const isScrollable = (element: HTMLElement) => {
  const { scrollHeight, clientHeight } = element
  return scrollHeight > clientHeight
}

interface ScrollDownButtonProps {
  actionLogsLength: number
  teamId: string
  channelId: string
}

const elId = 'scrollable'

const ScrollDownButton: FC<ScrollDownButtonProps> = ({
  actionLogsLength,
  teamId,
  channelId,
}) => {
  const [isScrolledToBottom, setIsScrolledToBottom] = useState(false)
  const [highlighted, setHighlighted] = useState(false)

  useEffect(() => {
    const ref = document.getElementById(elId) as HTMLDivElement
    const handleScroll = () => {
      if (ref) {
        const { scrollTop, scrollHeight, offsetHeight } = ref
        /*
         * when (scrollTop == scrollHeight - offsetHeight), the scroll is at
         * the bottom; the event is triggered before the scrolling has
         * completed, so we need some tolerance
         */
        const isScrolledToBottom =
          Math.abs(scrollTop - (scrollHeight - offsetHeight)) < TOLERANCE
        if (isScrolledToBottom) {
          setHighlighted(false)
        }
        setIsScrolledToBottom(isScrolledToBottom)
      }
    }

    if (ref) {
      if (!isScrollable(ref)) {
        setIsScrolledToBottom(true)
      }

      ref.addEventListener('scroll', handleScroll)
    }

    return () => {
      if (ref) {
        ref.removeEventListener('scroll', handleScroll)
      }
    }
  }, [teamId, channelId, setIsScrolledToBottom, setHighlighted])

  /*
   * highlight when new action logs come in, but teamId and channelId
   * stay the same (if they change, do not highlight, because the action log
   * list will be scrolled to the bottom anyway)
   */
  const prevActionLogsLength = useRef(actionLogsLength)
  const prevTeamId = useRef(teamId)
  const prevChannelId = useRef(channelId)
  useEffect(() => {
    const ref = document.getElementById(elId) as HTMLDivElement
    if (prevTeamId.current === teamId && prevChannelId.current === channelId) {
      if (
        ref &&
        isScrollable(ref) &&
        actionLogsLength > prevActionLogsLength.current
      ) {
        setHighlighted(true)
        setIsScrolledToBottom(false)
      }
    } else {
      setHighlighted(false)
    }

    prevActionLogsLength.current = actionLogsLength
    prevTeamId.current = teamId
    prevChannelId.current = channelId
  }, [actionLogsLength, teamId, channelId])

  const handleClick = useCallback(() => {
    const ref = document.getElementById(elId) as HTMLDivElement

    if (ref) {
      ref.scrollTo({
        top: ref.scrollHeight,
        behavior: 'smooth',
      })
    }
  }, [])

  return (
    <Button
      icon='arrow-down'
      minimal
      onClick={handleClick}
      rightIcon={highlighted ? <Dot color={Colors.RED3} /> : undefined}
      disabled={isScrolledToBottom}
      title={isScrolledToBottom ? 'Already scrolled down' : undefined}
      intent={highlighted ? 'warning' : undefined}
    >
      {highlighted ? <b>Scroll down</b> : 'Scroll down'}
    </Button>
  )
}

export default ScrollDownButton
