import React from 'react'
import { Platform } from 'react-native'

import { useSafeLayoutEffect } from '../utils/useSafeLayoutEffect'
import { StackWrapBox } from './StackWrapBox'
import { StackWrapGap } from './StackWrapGap'

// In Jest/CI/SSR, global CSS isn't always available and doesn't always have .supports method
const cssSupports = (property, value) =>
  Platform.OS === 'web' &&
  typeof window !== 'undefined' &&
  typeof window.CSS?.supports === 'function' &&
  window.CSS.supports(property, value)

// CSS.supports needs an example of the type of value you intend to use.
// Will be an integer appended `px` after hooks and JSX styles are resolved.
const exampleGapValue = '1px'

/**
 * StackWrap is an alternative to StackView where the spaced items are allowed to wrap.
 *
 * As well as providing space between the items, StackWrap provides `gap` space between
 * wrapped lines of items. By default, this `gap` is the same as the gap between spaced items.
 * If a different spacing is desired between wrapped lines, pass a spacing value to the `gap` prop.
 *
 * On web, when `gap` equals `space`, the server and the hydrating client both start on
 * `StackWrapGap`, since every supported browser has CSS `gap`. `StackWrapBox` renders on native,
 * when `gap` differs from `space`, and on a browser that reports no `gap` support after mount.
 */
export const StackWrap = React.forwardRef((props, ref) => {
  const { space } = props
  // Don't apply separate gap if `null` or `undefined`, so can be unset in Storybook etc
  const gap = props.gap ?? space
  const gapEqualsSpace = gap === space
  // Start on the implementation the client keeps, or hydration reflows the wrap (#7300).
  const [canUseCSSGap, setCanUseCSSGap] = React.useState(Platform.OS === 'web' && gapEqualsSpace)

  // If possible, use the cleaner implementation that applies CSS `gap` styles to the container,
  // preserving direct parent-child relationships between the container and each item, which
  // can result in clearer descriptions on some screen readers (e.g. radio "X of Y" on MacOS).
  // Else, use the fallback implementation which renders a `Box` component around each child.
  const Component = canUseCSSGap ? StackWrapGap : StackWrapBox
  useSafeLayoutEffect(() => {
    setCanUseCSSGap(gapEqualsSpace && cssSupports('gap', exampleGapValue))
  }, [gapEqualsSpace])

  return <Component ref={ref} {...props} />
})
StackWrap.displayName = 'StackWrap'

StackWrap.propTypes = StackWrapBox.propTypes
