import * as React from 'react'

export type DirectionValue = 'ltr' | 'rtl' | 'auto'

export interface DirectionContextValue {
  /** Current direction */
  direction: DirectionValue
  /** Update the direction */
  setDirection: (dir: DirectionValue) => void
}

const DirectionContext = React.createContext<DirectionContextValue>({
  direction: 'ltr',
  setDirection: () => {},
})

export interface DirectionProviderProps {
  /** Initial direction value */
  direction?: DirectionValue
  /** Children to wrap */
  children: React.ReactNode
  /** Callback when direction changes */
  onChange?: (direction: DirectionValue) => void
}

function DirectionProvider({
  direction: directionProp = 'ltr',
  children,
  onChange,
}: DirectionProviderProps) {
  const [direction, setDirectionState] = React.useState<DirectionValue>(directionProp)

  React.useEffect(() => {
    setDirectionState(directionProp)
  }, [directionProp])

  // Observe changes to the html dir attribute
  React.useEffect(() => {
    const htmlEl = document.documentElement
    const observer = new MutationObserver(() => {
      const dir = htmlEl.getAttribute('dir') as DirectionValue | null
      if (dir === 'ltr' || dir === 'rtl' || dir === 'auto') {
        setDirectionState(dir)
        onChange?.(dir)
      }
    })
    observer.observe(htmlEl, { attributes: true, attributeFilter: ['dir'] })
    return () => observer.disconnect()
  }, [onChange])

  const setDirection = React.useCallback(
    (dir: DirectionValue) => {
      setDirectionState(dir)
      onChange?.(dir)
    },
    [onChange]
  )

  const contextValue = React.useMemo(() => ({ direction, setDirection }), [direction, setDirection])

  return (
    <DirectionContext.Provider value={contextValue}>
      <div data-slot="direction-provider" dir={direction}>
        {children}
      </div>
    </DirectionContext.Provider>
  )
}

function useDirection(): DirectionContextValue {
  return React.useContext(DirectionContext)
}

export { DirectionProvider, useDirection, DirectionContext }
