import { Children, ReactElement, useEffect, useMemo } from 'react'

import { styled, useStyleConfig, vui, VuiComponent } from '../core'
import { List } from '../list'
import { cs, filterUndefined } from '../utils'
import { TreeProvider } from './context'
import { TreeItemId, TreeItemProps, TreeProps } from './tree.types'
import TreeIcon from './treeIcon'
import TreeItem from './treeItem'
import TreeText from './treeText'
import { useTreeState } from './useTreeState'

export const TreeBase = styled.divBox`
  display: flex;
  height: auto;
  align-content: flex-start;
  flex-direction: column;
`

/** Displays a tree of tree link items and optional heading. Exposes some props to the children via context. */
export const Tree = vui<'div', TreeProps>((props, ref) => {
  const { activeItemId, children, className, iconCollapse, iconExpand, items, onClickItem, size, variant, ...rest } =
    props
  const styles = useStyleConfig('Tree', props)

  const { itemsInternal, setItemsInternal, activeItemIndex, setActiveItemIndex } = useTreeState(activeItemId)

  const context = useMemo(() => filterUndefined({ size, variant }), [size, variant])

  const iconCollapseInternal = iconCollapse ? iconCollapse : variant === 'default' ? 'falAngleRight' : 'falMinus'
  const iconExpandInternal = iconExpand ? iconExpand : variant === 'default' ? 'falAngleDown' : 'falPlus'

  const transformChildrenToItems = (children: any) => {
    const t: TreeItemProps[] = []

    if (children) {
      ;(Children.toArray(children) as ReactElement[]).forEach((child: ReactElement<TreeItemProps>, index: number) => {
        if (child?.props?.text) {
          let items: TreeItemProps[] = []

          if (child.props.children) {
            items = transformChildrenToItems(child.props.children) as unknown as TreeItemProps[]
          }

          t.push({
            id: child.props.id,
            text: child.props.text,
            isActive: child.props.isActive,
            items: child.props.items || items,
            isCollapsed: child.props.isCollapsed,
            disabled: child.props.disabled,
            onClickTreeItem: onClickTreeItem,
          } as unknown as TreeItemProps)
        }
      })
    }

    return t
  }

  useEffect(() => {
    if (items) {
      setItemsInternal(items as TreeItemProps[])
      return
    }

    const t: TreeItemProps[] = []
    if (children) {
      const transformed = transformChildrenToItems(children) as unknown as TreeItemProps[]
      t.push(...transformed)
    }
    setItemsInternal(t)
    if (activeItemId !== undefined && t?.find((i: TreeItemProps) => i.id === activeItemId)) {
      setActiveItemIndex(activeItemId)
    }
  }, [children, activeItemId])

  const onClickTreeItem = (id: TreeItemId) => {
    setActiveItemIndex(id)
    if (onClickItem) {
      onClickItem(id)
    }
  }

  return (
    <TreeProvider value={context}>
      <TreeBase className={cs('vui-tree', className)} ref={ref} {...styles.container} {...rest}>
        <List role="tree" w={1}>
          {itemsInternal?.map(({ id, isActive, ...props }, index: number) => {
            return (
              <TreeItem
                activeItemIndex={activeItemIndex}
                iconCollapse={iconCollapseInternal}
                iconExpand={iconExpandInternal}
                id={id}
                isActive={isActive ? isActive : activeItemIndex ? activeItemIndex === id : false}
                isFirstLevel={true}
                key={id ?? index}
                onClickTreeItem={onClickTreeItem}
                {...props}
              />
            )
          })}
        </List>
      </TreeBase>
    </TreeProvider>
  )
}) as VuiComponent<'div', TreeProps> & {
  Icon: typeof TreeIcon
  Item: typeof TreeItem
  Text: typeof TreeText
}

Tree.Icon = TreeIcon
Tree.Item = TreeItem
Tree.Text = TreeText
Tree.displayName = 'Tree'

export default Tree
