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

import { SideNavItemContent } from './SideNavItemContent'
import { ExpandCollapsePanel } from '../ExpandCollapse/ExpandCollapsePanel'
import { getTokensPropType, selectTokens } from '../utils/props/tokens'
import { variantProp } from '../utils/props/variantProp'
import { componentPropType } from '../utils/props/componentPropType'
import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'

const selectPanelTokens = ({ borderWidth, borderColor, backgroundColor }) => ({
  contentPanelBackgroundColor: backgroundColor,
  borderBottomWidth: borderWidth,
  borderColor
})

/**
 Expandable content areas for use within `SideNav`.

 This component can only be accessed as a name-spaced component: `SideNavItemsGroup`.

 `SideNavItemsGroup` contains a label and a list of items. Items can link to in-page elements or route to other pages.

 ## Usage Criteria
 - Use `SideNavItemsGroup` with large pages that have multiple sections
 */
export const SideNavItemsGroup = React.forwardRef(
  (
    {
      children,
      label,
      openGroups,
      groupId,
      isActive = false,
      variant,
      tokens,
      itemTokens,
      onToggle
    },
    ref
  ) => {
    // A SideNav control uses the same style and theme as SideNavItem, with a 'parent' variant,
    // plus control-specific tokens from the SideNavItemsGroup theme (e.g. open/close icon, etc).
    const getAppearance = (appearance) => ({ ...variant, ...appearance, active: isActive })
    const getItemAppearance = (appearance) => ({ ...getAppearance(appearance), type: 'parent' })

    const getGroupTokens = useThemeTokensCallback('SideNavItemsGroup', tokens, variant)
    const getItemTokens = useThemeTokensCallback('SideNavItem', itemTokens, variant)

    const getPanelTokens = (appearance) =>
      selectTokens('ExpandCollapsePanel', {
        ...staticTokens.panel,
        ...getGroupTokens(getAppearance(appearance)),
        ...selectPanelTokens(getItemTokens(getItemAppearance(appearance)))
      })

    const getControlTokens = (appearance) => ({
      ...selectTokens('ExpandCollapseControl', {
        ...getItemTokens(getItemAppearance(appearance)), // main style from SideNavItem
        ...getGroupTokens(getAppearance(appearance)) // control-specific tokens like icon etc,
      }),
      ...staticTokens.control
    })

    const controlContent = (controlState) => {
      const currentItemTokens = getItemTokens(getItemAppearance(controlState))
      return (
        <SideNavItemContent tokens={{ ...currentItemTokens, ...staticTokens.content }}>
          {label}
        </SideNavItemContent>
      )
    }

    return (
      <ExpandCollapsePanel
        ref={ref}
        openIds={openGroups}
        panelId={groupId}
        onToggle={onToggle}
        tokens={getPanelTokens}
        controlTokens={getControlTokens}
        control={controlContent}
        accessibilityState={{ active: isActive }} // ExpandCollapsePanel handles expanded state
        disableMobileScrollBuffer
      >
        {children}
      </ExpandCollapsePanel>
    )
  }
)

const staticTokens = {
  panel: {
    borderWidth: 0,
    marginBottom: 0
  },
  control: { borderWidth: 0, textLine: null },
  content: { accentWidth: 0 }
}

SideNavItemsGroup.displayName = 'SideNavItemsGroup'

SideNavItemsGroup.propTypes = {
  /**
   * Specifies the links contained within. It may only contain `SideNavItem`.
   */
  children: componentPropType('Item'),
  /**
   * Text content of the group's parent `SideNavItem`.
   */
  label: PropTypes.string.isRequired,
  /**
   * @ignore
   * Set internally in `SideNav` render function - used to keep track of expanded items groups.
   */
  groupId: PropTypes.string,
  /**
   * @ignore
   * Set internally in `SideNav` render function. Called when the group is expanded/collapsed.
   */
  onToggle: PropTypes.func,
  /**
   * @ignore
   * Set internally in `SideNav` render function. Contains `groupId`s of currently open groups.
   */
  openGroups: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
  /**
   * @ignore
   * Set internally in `SideNav` render function. Used to mark group containing the currently active `SideNavItem`.
   */
  isActive: PropTypes.bool,
  variant: variantProp.propType,
  tokens: getTokensPropType('SideNavItemsGroup'),
  /**
   * Custom tokens for `SideNavItem`
   */
  itemTokens: getTokensPropType('SideNavItem')
}
