import React from 'react'
import { Pressable, Platform } from 'react-native'
import PropTypes from 'prop-types'
import { a11yProps } from '../utils/props/a11yProps'
import { getTokensPropType } from '../utils/props/tokens'
import { hrefAttrsProp } from '../utils/props/hrefAttrsProp'
import { linkProps } from '../utils/props/linkProps'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { verticalAlignRow } from '../ThemeProvider/utils/styles'
import { SideNavItemContent } from './SideNavItemContent'

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

function selectItemStyles({
  backgroundColor,
  borderColor,
  borderWidth,
  borderStyle,
  paddingLeft,
  paddingRight,
  paddingTop,
  paddingBottom,
  justifyContent,
  verticalAlign
}) {
  return {
    backgroundColor,
    borderBottomColor: borderColor,
    borderBottomWidth: borderWidth,
    borderBottomStyle: borderStyle,
    paddingLeft,
    paddingRight,
    paddingTop,
    paddingBottom,
    justifyContent,
    ...verticalAlignRow(verticalAlign)
  }
}

/**
 `SideNavItem` is a navigational element that is used within `SideNav` or `SideNavItemsGroup`.

 This component can only be accessed as a name-spaced component: `SideNavItem`.
 */
export const SideNavItem = React.forwardRef(
  (
    {
      children,
      itemId,
      groupId,
      onPress,
      isActive = false,
      isExpanded = false,
      tokens,
      variant,
      href,
      accessibilityRole = 'link',
      testID,
      ...props
    },
    ref
  ) => {
    const handlePress = () => onPress(itemId, groupId)

    const { hrefAttrs, rest } = hrefAttrsProp.bundle(props)
    const selectedProps = selectProps({
      accessibilityRole,
      href,
      onPress: handlePress,
      hrefAttrs,
      ...rest
    })

    const getTokens = useThemeTokensCallback('SideNavItem', tokens, variant)
    const getAppearanceState = ({ hovered, focused }) => ({
      hover: hovered,
      active: isActive,
      expanded: isExpanded,
      focus: focused
    })
    const getPressableStyle = (pressableState) => ({
      ...selectItemStyles(getTokens(getAppearanceState(pressableState))),
      ...(Platform.OS === 'web' ? { outline: 'none' } : {})
    })

    return (
      <Pressable
        ref={ref}
        style={getPressableStyle}
        accessibilityState={{ selected: isActive }}
        {...selectedProps}
      >
        {(pressableState) => {
          const themeTokens = getTokens(getAppearanceState(pressableState))
          return <SideNavItemContent tokens={themeTokens}>{children}</SideNavItemContent>
        }}
      </Pressable>
    )
  }
)
SideNavItem.displayName = 'SideNavItem'

SideNavItem.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Text content of the `Item`.
   */
  children: PropTypes.node.isRequired,
  /**
   * @ignore
   * Set internally in `SideNav` render function - used to keep track of active item.
   */
  itemId: PropTypes.string,
  /**
   * @ignore
   * Set internally in `SideNav` render function - used to keep track of expanded items groups.
   */
  groupId: PropTypes.string,
  /**
   * Called when the item is pressed. Use instead of `href` for items that do not navigate.
   */
  onPress: PropTypes.func,
  /**
   * URL the item navigates to. Rendered as `<a href>` on web.
   */
  href: PropTypes.string,
  /**
   * On Web if href is passed, React Native Web maps this object's props to
   * `rel`, `target` and `download` attrs.
   */
  hrefAttrs: PropTypes.shape(hrefAttrsProp.types),
  /**
   * @ignore
   * Set internally in `SideNav` render function.
   */
  isActive: PropTypes.bool,
  /**
   * @ignore
   * Set internally in `SideNavItemsGroup` render function. Used to mark expanded `ItemsGroup` parent.
   */
  isExpanded: PropTypes.bool,
  accessibilityRole: PropTypes.string,
  /**
   * Identifier for testing purposes.
   */
  testID: PropTypes.number,
  tokens: getTokensPropType('SideNavItem'),
  variant: variantProp.propType
}
