import React, { useMemo } from 'react'
import TreeLeaf from './tree-leaf'
import TreeFolder from './tree-folder'
import { TreeContext } from './tree-context'
import { tuple } from '../utils/prop-types'
import { sortChildren } from './/tree-help'

const TreeValueType = tuple('directory', 'leaf')

const directoryType = TreeValueType[0]

export type TreeValue = {
  type?: (typeof TreeValueType)[number] | string
  name: string
  extra?: string
  children?: Array<TreeValue>
}

interface Props {
  value?: Array<TreeValue>
  initialExpand?: boolean
  onClick?: (path: string) => void
  selectableNodes?: boolean
  className?: string
}

const defaultProps = {
  initialExpand: false,
  type: TreeValueType[1],
  className: ''
}

type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
export type TreeProps = Props & typeof defaultProps & NativeAttrs

const makeLeafs = (value: Array<TreeValue> = []) => {
  if (!value || !value.length) return null
  return value
    .slice()
    .sort((a, b) => {
      if (a.type !== b.type) return a.type !== directoryType ? 1 : -1

      return `${a.name}`.charCodeAt(0) - `${b.name}`.charCodeAt(0)
    })
    .map((item, index) => {
      if (item.type === directoryType)
        return (
          <TreeFolder name={item.name} extra={item.extra} key={`folder-${item.name}-${index}`}>
            {makeLeafs(item.children)}
          </TreeFolder>
        )
      return <TreeLeaf name={item.name} extra={item.extra} key={`leaf-${item.name}-${index}`} />
    })
}

const Tree: React.FC<React.PropsWithChildren<TreeProps>> = ({
  children,
  onClick,
  selectableNodes,
  initialExpand,
  value,
  className,
  ...props
}) => {
  const isImperative = Boolean(value && value.length > 0)
  const onLeafClick = (path: string) => {
    onClick && onClick(path)
  }
  const onNodeClick = selectableNodes
    ? (path: string) => {
        onClick && onClick(path)
      }
    : undefined

  const initialValue = useMemo(
    () => ({
      onLeafClick,
      onNodeClick,
      initialExpand,
      isImperative
    }),
    [initialExpand, isImperative, onLeafClick, onNodeClick]
  )

  const customChildren = isImperative ? makeLeafs(value) : sortChildren(children, TreeFolder)

  return (
    <TreeContext.Provider value={initialValue}>
      <div className={`tree ${className}`} {...props}>
        {customChildren}
        <style jsx>{`
          .tree {
            padding-left: 1.375rem;
          }
        `}</style>
      </div>
    </TreeContext.Provider>
  )
}

type TreeComponent<P> = React.FC<P> & {
  Leaf: typeof TreeLeaf
  File: typeof TreeLeaf
  Folder: typeof TreeFolder
}

type ComponentProps = Partial<typeof defaultProps> &
  Omit<Props, keyof typeof defaultProps> &
  NativeAttrs

Tree.defaultProps = defaultProps

export default Tree as TreeComponent<ComponentProps>
