import React from 'react'
import PropTypes from 'prop-types'

import { ExpandCollapse } from '../ExpandCollapse/ExpandCollapse'
import { SideNavItem } from './SideNavItem'
import { SideNavItemsGroup } from './SideNavItemsGroup'
import { useThemeTokens } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { componentPropType } from '../utils/props/componentPropType'
import { getTokensPropType } from '../utils/props/tokens'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { viewProps } from '../utils/props/viewProps'

const selectContainerTokens = ({ borderWidth, borderStyle, borderColor }) => {
  return {
    borderTopWidth: borderWidth,
    borderStyle,
    borderColor
  }
}

const selectItemTokens = (tokens = {}, isLastItem = false) => ({
  ...tokens,
  ...(isLastItem
    ? {
        borderWidth: 0
      }
    : {})
})

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

/**
 ## Usage Criteria
 - Use in conjunction with a large amount of educational / informational content
 - Allow the user to navigate between options frequently and efficiently
 */
export const SideNav = React.forwardRef(
  ({ children, variant = {}, tokens, accordion = true, itemTokens, groupTokens, ...rest }, ref) => {
    const themeTokens = useThemeTokens('SideNav', tokens, variant)
    const [active, setActive] = React.useState({ groupId: undefined, itemId: undefined })

    const onItemPress = (itemId, groupId) => {
      setActive({ itemId, groupId })
    }

    const isItemActive = (itemId, groupId) => {
      return active.groupId === groupId && active.itemId === itemId
    }

    return (
      <ExpandCollapse
        ref={ref}
        maxOpen={accordion ? 1 : null}
        tokens={selectContainerTokens(themeTokens)}
        {...selectProps(rest)}
      >
        {({ openIds, onToggle }) => {
          const renderItem = (item, index, groupId, isLastItem = false) => {
            const { itemId = `item-${index}`, onPress } = item.props
            const handlePress = (...args) => {
              onItemPress(...args)
              if (onPress) onPress(...args)
            }

            return (
              <SideNavItem
                {...item.props}
                key={itemId}
                itemId={itemId}
                groupId={groupId}
                variant={groupId ? { ...variant, type: 'child' } : variant}
                tokens={selectItemTokens(itemTokens, isLastItem)}
                isActive={isItemActive(itemId, groupId)}
                onPress={handlePress}
              />
            )
          }

          return React.Children.map(children, (child, index) => {
            // iterate over children and identify them internally to later reference expanded groups and active items
            if (child.type === SideNavItem) return renderItem(child, index)

            if (child.type === SideNavItemsGroup) {
              const { groupId = `group-${index}` } = child.props
              const isGroupActive = active.itemId !== undefined && active.groupId === groupId
              const handleToggle = (event) => onToggle(groupId, event)

              return (
                <SideNavItemsGroup
                  {...child.props}
                  key={groupId}
                  groupId={groupId}
                  variant={variant}
                  tokens={groupTokens}
                  itemTokens={itemTokens}
                  openGroups={openIds}
                  isActive={isGroupActive}
                  onToggle={handleToggle}
                >
                  {React.Children.map(child.props.children, (item, itemIndex) =>
                    renderItem(
                      item,
                      itemIndex,
                      groupId,
                      itemIndex === child.props.children.length - 1
                    )
                  )}
                </SideNavItemsGroup>
              )
            }

            return null
          })
        }}
      </ExpandCollapse>
    )
  }
)
SideNav.displayName = 'SideNav'

SideNav.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * Specifies the structure and links of the `SideNav`. It may only consist of `SideNavItem` and `SideNavItemsGroup`.
   */
  children: componentPropType(['Item', 'ItemsGroup']),
  /**
   * Identifies if only one `SideNavItemsGroup` should be open at a time.
   */
  accordion: PropTypes.bool,
  variant: variantProp.propType,
  tokens: getTokensPropType('SideNav'),
  /**
   * Custom tokens for `SideNavItem`
   */
  itemTokens: getTokensPropType('SideNavItem'),
  /**
   * Custom tokens for `SideNavItemsGroup`
   */
  groupTokens: getTokensPropType('SideNavItemsGroup')
}
