import React from 'react'
import PropTypes from 'prop-types'
import { Platform, View } from 'react-native'
import { a11yProps } from '../utils/props/a11yProps'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { viewProps } from '../utils/props/viewProps'
import { layoutTags, getA11yPropsFromHtmlTag } from '../utils/a11y/semantics'
import { useScroll } from './ScrollContext'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, viewProps])

const DEFAULT_TAG = 'li'
const DATA_SCROLL_ITEM = 'scrollItem'
const INITIAL_DIMENSION = 0
const TAB_INDEX = 0

const selectContainerStyle = ({ itemWidth, itemHeight }) => {
  const style = {}
  if (itemWidth > INITIAL_DIMENSION) {
    style.width = itemWidth
  }
  if (itemHeight > INITIAL_DIMENSION) {
    style.height = itemHeight
  }
  return style
}

/**
 * The `ScrollItem` component wraps individual items within a `Scroll` container. Each item
 * is individually focusable and reports its natural dimensions so the parent can apply uniform
 * sizing across all items.
 *
 * ## Props
 *
 * - Use `children` to provide the content of the scroll item
 * - Use `tag` to set the HTML tag of the outer container (defaults to `'li'`)
 *
 */
const ScrollItem = React.forwardRef(({ children, tag = DEFAULT_TAG, ...rest }, ref) => {
  const { itemWidth, itemHeight, onItemLayout } = useScroll()

  const handleLayout = React.useCallback(
    ({
      nativeEvent: {
        layout: { width, height }
      }
    }) => {
      onItemLayout?.(width, height)
    },
    [onItemLayout]
  )

  const selectedProps = selectProps({
    ...rest,
    ...getA11yPropsFromHtmlTag(tag, rest.accessibilityRole)
  })

  return (
    <View
      ref={ref}
      style={selectContainerStyle({ itemWidth, itemHeight })}
      onLayout={handleLayout}
      dataSet={{ [DATA_SCROLL_ITEM]: true }}
      {...(Platform.OS === 'web' ? { tabIndex: TAB_INDEX } : { focusable: true })}
      {...selectedProps}
    >
      {children}
    </View>
  )
})

ScrollItem.displayName = 'ScrollItem'

ScrollItem.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Content of the scroll item
   */
  children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
  /**
   * Sets the HTML tag of the outer container. Defaults to `'li'`.
   */
  tag: PropTypes.oneOf(layoutTags)
}

const MemoizedScrollItem = React.memo(ScrollItem)
export { MemoizedScrollItem as ScrollItem }
