'use client'

import {
  useEffect,
  useRef,
  useState,
  useSyncExternalStore,
  type CSSProperties,
  type ReactNode,
} from 'react'
import {
  createGlyphRain,
  supportsHtmlInCanvas,
  type GlyphRainInstance,
  type GlyphRainOptions,
} from '../core/createGlyphRain'

export type GlyphRainProps = GlyphRainOptions & {
  children: ReactNode
  className?: string
  style?: CSSProperties
}

const emptySubscribe = () => () => {}

export function GlyphRain({
  children,
  className,
  style,
  ...options
}: GlyphRainProps) {
  const sourceRef = useRef<HTMLCanvasElement>(null)
  const contentRef = useRef<HTMLDivElement>(null)
  const outputRef = useRef<HTMLCanvasElement>(null)
  const instanceRef = useRef<GlyphRainInstance | null>(null)
  const [initialOptions] = useState(options)
  const [failed, setFailed] = useState(false)

  const supported = useSyncExternalStore(
    emptySubscribe,
    supportsHtmlInCanvas,
    () => false,
  )
  const native = supported && !failed

  useEffect(() => {
    const source = sourceRef.current
    const content = contentRef.current
    const output = outputRef.current
    if (!source || !content || !output) return
    instanceRef.current = createGlyphRain(
      { source, content, output },
      initialOptions,
    )
    if (native && !instanceRef.current) setFailed(true)
    return () => {
      instanceRef.current?.destroy()
      instanceRef.current = null
    }
  }, [initialOptions, native])

  useEffect(() => {
    instanceRef.current?.setOptions(options)
  })

  return (
    <div className={className} style={{ position: 'relative', ...style }}>
      <canvas
        ref={sourceRef}
        // @ts-expect-error experimental html-in-canvas attribute
        layoutsubtree="true"
        suppressHydrationWarning
        style={
          native
            ? {
                position: 'absolute',
                inset: 0,
                width: '100%',
                height: '100%',
              }
            : { display: 'none' }
        }
      >
        {native ? (
          <div
            ref={contentRef}
            style={{
              position: 'relative',
              width: '100%',
              height: '100%',
              overflow: 'auto',
            }}
          >
            {children}
          </div>
        ) : null}
      </canvas>
      {!native ? (
        <div
          ref={contentRef}
          style={{
            position: 'relative',
            width: '100%',
            height: '100%',
            overflow: 'auto',
          }}
        >
          {children}
        </div>
      ) : null}
      <canvas
        ref={outputRef}
        aria-hidden
        style={{
          position: 'absolute',
          inset: 0,
          width: '100%',
          height: '100%',
          pointerEvents: 'none',
        }}
      />
    </div>
  )
}

export default GlyphRain
