import React, { Component } from 'react'
import { node, string, bool } from 'prop-types'
import { Reference, Manager, Frame } from '@swrve/offscreen'
import { Icon } from '@swrve/icons'
import Downshift from 'downshift'
import classnames from 'classnames'

import NavItem from '../navItem/NavItem'
import NavOptions from './NavOptions'

class NavGroup extends Component {
  childrenRef = null
  state = {
    open: false,
    active: false
  }

  // Set up ref on children menu options
  setchildrenRefRef = element => (this.childrenRef = element)

  // Check if any sublink routes are currently active, used to open or close menu
  checkItemsActive = () => this.childrenRef && !!this.childrenRef.querySelector('a.active')

  componentDidMount() {
    const containsActiveLink = this.checkItemsActive()
    if (containsActiveLink) {
      this.setState({
        active: containsActiveLink,
        open: !this.props.collapsed
      })
    }
  }

  UNSAFE_componentWillUpdate({ activeItem, collapsed, floatMenu }) {
    const menuToggled = collapsed !== this.props.collapsed
    const otherMenuOpened = activeItem !== this.props.activeItem

    // Toggle menu when collapsing, if not active then always close
    if (menuToggled) {
      this.setState(({ open }) => ({
        open: this.state.active ? !collapsed : false
      }))
      // If other sub-menu open then close current
    } else if (otherMenuOpened && this.state.open) {
      this.setState({ open: false })
    }
  }

  componentDidUpdate({ collapsed }, { active }) {
    const containsActiveLink = this.checkItemsActive()
    if (!this.state.active === containsActiveLink && !collapsed) {
      this.setState({ active: containsActiveLink, open: containsActiveLink })
    }
  }

  /**
   * State Toggle Handlers
   */

  // Toggle Menu with Downshift onChange Event
  handleToggle = ({ isOpen }) =>
    this.setState({ open: isOpen }, this.props.setActiveItem(this.props.label))

  // Toggle Menu on Enter key press
  handleKeyEnter = e => e.key === 'Enter' && this.setState(({ open }) => ({ open: !open }))

  // Toggle Menu with :hover event (only when menu is collapsed)
  getListItemProps = openOnHover => ({
    onMouseEnter: () => openOnHover && this.setState({ open: true }),
    onMouseLeave: () => openOnHover && this.setState({ open: false })
  })

  /**
   * Custom Event Handling for Downshift
   */
  stateReducer = (state, changes) => {
    switch (changes.type) {
      case Downshift.stateChangeTypes.clickItem:
      case Downshift.stateChangeTypes.blurButton:
        return {
          ...changes,
          isOpen: state.isOpen
        }
      case Downshift.stateChangeTypes.mouseUp:
        return {
          ...changes,
          isOpen: !this.props.floatMenu ? state.isOpen : false
        }
      default:
        return changes
    }
  }

  render() {
    const {
      children,
      label,
      collapsed,
      floatMenu,
      automation,
      setActiveItem,
      activeItem,
      ...props
    } = this.props
    const { open, active } = this.state

    const buttonStyles = classnames({ active }, { open })
    const isMenuFloating = (collapsed || floatMenu) && open

    const navOptions = (
      <NavOptions
        children={children}
        setRef={this.setchildrenRefRef}
        label={label}
        open={open}
        collapsed={isMenuFloating}
      />
    )

    return (
      <Downshift
        defaultIsOpen={open}
        isOpen={open}
        onStateChange={this.handleToggle}
        stateReducer={this.stateReducer}
      >
        {({ isOpen, getToggleButtonProps, getItemProps }) => (
          <li className="my-3" {...this.getListItemProps(collapsed)} data-automation={automation}>
            <Manager>
              <div>
                <Reference>
                  {({ ref }) => (
                    <NavItem
                      {...getToggleButtonProps({
                        className: buttonStyles,
                        tabIndex: 0,
                        onKeyDown: this.handleKeyEnter,
                        innerRef: ref,
                        label,
                        ...props
                      })}
                    >
                      {!floatMenu && <Icon name="arrow" size="small" className="arrow" />}
                    </NavItem>
                  )}
                </Reference>

                {isMenuFloating ? (
                  <Frame
                    arrow
                    className="floating-list"
                    offsetX="mx-6"
                    placement={floatMenu ? 'right-end' : 'right-start'}
                  >
                    {navOptions}
                  </Frame>
                ) : (
                  navOptions
                )}
              </div>
            </Manager>
          </li>
        )}
      </Downshift>
    )
  }
}

NavGroup.propTypes = {
  /** List of subItems for Navigation group */
  children: node,
  /** Determine wether the menu is collapsed or not */
  collapsed: bool,
  /** Name for the Navigation group */
  label: string,
  /** Determine if menu show always show as floated menu */
  floatMenu: bool,
  /** Label for data-automation tag */
  automation: string
}

NavGroup.defaultProps = {
  collapsed: false,
  floatMenu: false,
  automation: ''
}

NavGroup.displayName = 'NavGroup'

export default NavGroup
