import React from 'react'
import PropTypes from 'prop-types'
import { AccessibilityInfo, Platform } from 'react-native'

const ScreenReaderContext = React.createContext(false)
const ReducedMotionContext = React.createContext(false)

// eslint-disable-next-line no-unused-vars
export const A11yInfoProvider = React.forwardRef(({ children }, _) => {
  const [reduceMotionEnabled, setReduceMotionEnabled] = React.useState(false)
  const [screenReaderEnabled, setScreenReaderEnabled] = React.useState(false)

  React.useEffect(() => {
    if (process.env.NODE_ENV === 'test') {
      // On Jest these effects do nothing but can cause `act` state change warnings
      // and "...after the Jest environment has been torn down" errors, so skip them.
      return () => {}
    }

    const motionSubscription = AccessibilityInfo.addEventListener(
      'reduceMotionChanged',
      setReduceMotionEnabled
    )

    const setInitialA11yInfo = async () => {
      const [initialReduceMotionEnabled, initialScreenReaderEnabled] = await Promise.all([
        AccessibilityInfo.isReduceMotionEnabled(),
        AccessibilityInfo.isScreenReaderEnabled()
      ])

      // Browsers can't detect screen readers; in RNW isScreenReaderEnabled() is always `true`
      // https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/exports/AccessibilityInfo/index.js#L14
      setScreenReaderEnabled(Platform.OS !== 'web' && !!initialScreenReaderEnabled)

      // RNW does support isReduceMotionEnabled looking for 'prefers-reduced-motion' state
      setReduceMotionEnabled(!!initialReduceMotionEnabled)
    }

    if (AccessibilityInfo.isReduceMotionEnabled && AccessibilityInfo.isScreenReaderEnabled) {
      setInitialA11yInfo()
    }

    return () => {
      // From react-native 0.65, AccessibilityInfo.removeEventListener is deprecated for `remove` on addEventListener return value
      if (typeof motionSubscription?.remove === 'function') {
        motionSubscription?.remove()
      } else if (typeof AccessibilityInfo.removeEventListener === 'function') {
        AccessibilityInfo.removeEventListener('reduceMotionChanged', setReduceMotionEnabled)
      }
    }
  }, [])

  return (
    <ReducedMotionContext.Provider value={reduceMotionEnabled}>
      <ScreenReaderContext.Provider value={screenReaderEnabled}>
        {children}
      </ScreenReaderContext.Provider>
    </ReducedMotionContext.Provider>
  )
})

A11yInfoProvider.displayName = 'A11yInfoProvider'

A11yInfoProvider.propTypes = {
  /**
   * The subtree that can read the device's screen reader and reduced-motion settings via the
   * `useA11yInfo` hook.
   */
  children: PropTypes.node.isRequired
}

export const useA11yInfo = () => {
  const screenReaderEnabled = React.useContext(ScreenReaderContext)
  const reduceMotionEnabled = React.useContext(ReducedMotionContext)

  return {
    reduceMotionEnabled,
    screenReaderEnabled
  }
}
