import type { TooltipProps } from '@mui/material'
import { useLayoutEffect, useRef, useState, type JSX, type Ref } from 'react'
import { Tooltip } from '../tooltip/tooltip'

const EMPTY_DEPENDENCIES: unknown[] = []

/**
 * An intelligent tooltip wrapper that automatically detects text overflow and displays a tooltip only when content is truncated.
 *
 * @remarks
 * Uses a render prop pattern. The child function receives a `ref` that must be attached to the element being monitored for overflow. Use the `dependencies` array to trigger re-evaluation when content or container size changes.
 *
 * @example
 * ```tsx
 * <SmartTooltip title="This is a long text that might get truncated">
 *   {({ ref }) => (
 *     <Typography ref={ref} noWrap sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
 *       This is a long text that might get truncated
 *     </Typography>
 *   )}
 * </SmartTooltip>
 * ```
 */
export function SmartTooltip<T extends HTMLElement>({
  title,
  dependencies = EMPTY_DEPENDENCIES,
  timeout = 500,
  TooltipProps,
  children,
}: {
  title: string | undefined
  dependencies?: unknown[]
  timeout?: number
  children: (props: { ref: Ref<T> }) => JSX.Element
  TooltipProps?: Partial<TooltipProps>
}) {
  const ref = useRef<T>(null)
  const [isOverflowing, setIsOverflowing] = useState(false)
  // Call sites pass a fresh `dependencies={[…]}` literal each render; key by
  // value so the effect does not churn ResizeObserver on referential churn.
  const dependenciesKey = JSON.stringify(dependencies)

  useLayoutEffect(() => {
    const checkOverflow = () => {
      const el = ref.current
      if (!el) return
      setIsOverflowing(
        el.scrollWidth > el.clientWidth || el.scrollHeight > el.clientHeight,
      )
    }

    // Initial measure after layout settles (fonts, flex collapse, …).
    const timerId = setTimeout(checkOverflow, timeout)
    // Re-measure when the element is resized (e.g. legend title reflows as
    // hover-faded actions collapse/expand).
    const el = ref.current
    const resizeObserver =
      el && typeof ResizeObserver !== 'undefined'
        ? new ResizeObserver(checkOverflow)
        : null
    if (el) resizeObserver?.observe(el)

    return () => {
      clearTimeout(timerId)
      resizeObserver?.disconnect()
    }
  }, [dependenciesKey, timeout])

  return (
    <Tooltip title={isOverflowing && title} {...TooltipProps}>
      {children({ ref })}
    </Tooltip>
  )
}
