import React, { useEffect, useMemo, useState } from 'react'

import Box from '../box'
import Button from '../button'
import { useStyleConfig, vui, VuiComponent } from '../core'
import Icon from '../icon'
import { cs, filterUndefined, isActivePath } from '../utils'
import { expandedWidth } from './consts'
import { SidemenuProvider } from './context'
import { SidemenuItemProps, SidemenuProps } from './sidemenu.types'
import SidemenuItem from './sidemenuItem'
import SidemenuTop from './sidemenuTop'

/** A collapsible side menu for navigation. */
export const Sidemenu = vui<'div', SidemenuProps>((props, ref) => {
  const {
    children,
    className,
    items,
    isExpanded = false,
    isSticky = false,
    size,
    variant,
    width = 280,
    onNavigate,
    ...rest
  } = props

  const [isExpandedHorizontally, setIsExpandedHorizontally] = useState(isExpanded)
  const context = useMemo(
    () => filterUndefined({ size, variant, isExpandedHorizontally }),
    [size, variant, isExpandedHorizontally],
  )

  const styles = useStyleConfig('Sidemenu', props)

  const isDark = variant === 'dark'

  useEffect(() => {
    setIsExpandedHorizontally(isExpanded)
  }, [isExpanded])

  const onToggle = () => setIsExpandedHorizontally(!isExpandedHorizontally)

  const w = isExpandedHorizontally ? width : expandedWidth
  const icon = `falArrow${isExpandedHorizontally ? 'Left' : 'Right'}`
  const justifyContent = isExpandedHorizontally ? 'flex-end' : 'center'

  function onItemClick(item: SidemenuItemProps) {
    item?.onClick?.()
    if (item?.path) onNavigate?.(item.path)
  }

  return (
    <SidemenuProvider value={context}>
      <Box
        className={cs('vui-sidemenu', className)}
        elevation="3"
        flexDirection="column"
        minWidth={0}
        overflowX="hidden"
        position={isSticky ? 'sticky' : 'static'}
        ref={ref}
        top={isSticky ? (top ? top : 0) : 'auto'}
        transitionDuration="normal"
        w={w}
        {...styles.container}
        {...rest}
      >
        <Box flexDirection="column" flexGrow={1} overflowX="hidden" overflowY="auto" w="100%">
          {items
            ? items?.map?.((item: SidemenuItemProps, key: number) => (
                <SidemenuItem
                  isActive={isActivePath(item?.path)}
                  key={key}
                  {...item}
                  onClick={() => onItemClick(item)}
                />
              ))
            : children}
        </Box>
        <Box className="vui-sidemenu-bottom" w="100%" {...styles.bottom}>
          <Button
            aria-label={isExpandedHorizontally ? 'Collapse' : 'Expand'}
            borderRadius={0}
            justifyContent={justifyContent}
            minH={size === 'lg' ? '56px' : '40px'}
            onClick={onToggle}
            size="md"
            variant={isDark ? 'tertiaryLight' : 'tertiaryDark'}
            w="100%"
          >
            <Icon name={icon} />
          </Button>
        </Box>
      </Box>
    </SidemenuProvider>
  )
}) as VuiComponent<'div', SidemenuProps> & {
  Top: typeof SidemenuTop
  Item: typeof SidemenuItem
}

Sidemenu.Top = SidemenuTop
Sidemenu.Item = SidemenuItem
Sidemenu.displayName = 'Sidemenu'

export default Sidemenu
