import { useTheme } from '@mui/material'
import type { PropsWithChildren } from 'react'
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
import { useInView } from 'react-intersection-observer'
import type { TextFitterProps } from './types.js'

const initialState = {
  x: 0,
  y: 0,
  width: 0,
  height: 0,
}

export const TextFitter: React.FC<PropsWithChildren<TextFitterProps>> = ({
  children,
  width = '100%',
  height,
  preserveAspectRatio = 'xMinYMid meet',
  textStyle,
  svgStyle,
  cropTop,
  cropBottom,
  onFit,
}) => {
  const theme = useTheme()
  const textRef = useRef<SVGTextElement>(null)
  const [viewBox, setViewBox] = useState<Partial<DOMRect>>(initialState)

  const [ref] = useInView({
    onChange(inView) {
      if (inView) {
        calculateBox()
      }
    },
  })

  const calculateBox = useCallback(() => {
    if (!textRef.current) {
      return
    }
    const box = textRef.current.getBBox()
    if (cropTop) {
      box.y += box.height * cropTop
      box.height -= box.height * cropTop
    }
    if (cropBottom) {
      box.height -= box.height * cropBottom
    }
    setViewBox(box)
    onFit?.()
  }, [cropBottom, cropTop, onFit])

  // biome-ignore lint/correctness/useExhaustiveDependencies: run only when children changes
  useLayoutEffect(() => {
    calculateBox()
  }, [calculateBox, children])

  useLayoutEffect(() => {
    if (document.fonts) {
      document.fonts.ready.then(() => {
        calculateBox()
      })
    }
  }, [calculateBox])

  return (
    <svg
      style={svgStyle}
      viewBox={`${viewBox.x} ${viewBox.y} ${viewBox.width} ${viewBox.height}`}
      width={width}
      height={height}
      // height={
      //   textRect.height && maxHeight && textRect.height >= maxHeight
      //     ? maxHeight
      //     : height
      // }
      preserveAspectRatio={preserveAspectRatio}
      fill={theme.vars.palette.text.primary}
      ref={ref}
    >
      <title>{children}</title>
      <text x={0} y={0} style={textStyle} ref={textRef}>
        {children}
      </text>
    </svg>
  )
}
