import React from "react"
import { last } from "lodash"
import { Icon } from "@/components"
import { convertSpecialCharacter } from "@/utils"

interface INode {
  anchor: string
  level: number
  text: string
  expand: boolean
  focus: boolean
  children?: INode[]
}

export type NodeTree = INode[]

const scrollToAnchor = (anchor: string) => {
  if (anchor) {
    const anchorElement = document.getElementById(anchor)
    anchorElement &&
      anchorElement.scrollIntoView({ block: "start", behavior: "smooth" })
  }
}

const toggleExpand = (node: INode, value?: boolean) =>
  typeof value === "undefined"
    ? (node.expand = !node.expand)
    : (node.expand = value)

const toggleCurrentLevel = (node: INode, nodeTree: NodeTree) => {
  nodeTree.map(el => {
    toggleExpand(el, el.anchor === node.anchor)
  })
}

const recursiveToggleExpand = (node: INode, nodeTree: NodeTree): boolean => {
  for (const item of nodeTree) {
    if (item.anchor === node.anchor) {
      toggleCurrentLevel(item.expand ? { ...node, anchor: "" } : node, nodeTree)
      return true
    } else {
      if (item.children && recursiveToggleExpand(node, item.children)) {
        toggleCurrentLevel(node, nodeTree)
      }
    }
  }
  return false
}

const nodeToAnchor = (node: INode, nodeTree: NodeTree) => {
  scrollToAnchor(node.anchor)
  recursiveToggleOnlyFocus(node, nodeTree)
}

const recursiveToggleOnlyFocus = (node: INode, nodeTree: NodeTree) => {
  for (const item of nodeTree) {
    item.focus = item.anchor === node.anchor
    if (item.children) recursiveToggleOnlyFocus(node, item.children)
  }
}

export const addCatalogueNode = (
  text: string,
  level: number,
  anchors: string[],
  nodeTree: NodeTree
) => {
  text = convertSpecialCharacter(text.replace(/<[^>]*>/g, "")) // 处理attr

  const count = anchors.filter(anchor => anchor === text).length
  let anchor = count ? `${text}${count}` : text
  anchor = anchor.replace(/\s|[\r\n]/g, "-").toLowerCase()

  anchors.push(anchor)

  const node = { anchor, level, text, expand: false, focus: false }

  if (nodeTree.length === 0) {
    nodeTree.push(node)
  } else {
    let lastItem = last(nodeTree) as INode
    if (node.level <= lastItem.level) {
      nodeTree.push(node)
    } else {
      for (let i = lastItem.level; i < 6 + 1; i++) {
        const { children } = lastItem

        if (!children) {
          lastItem.children = [node]
          break
        }
        lastItem = last(children) as INode
        if (node.level <= lastItem.level) {
          children.push(node)
          break
        }
      }
    }
  }

  return { anchor, anchors, nodeTree }
}

export const renderOneNode = (
  items: NodeTree,
  nodeTree: NodeTree,
  setCatalogueNodeTree: React.Dispatch<React.SetStateAction<NodeTree>>
) => {
  return items.map((node, index) => (
    <React.Fragment key={index}>
      <div
        key={node.anchor}
        className={`catalogue-node catalogue-expand-${node.expand} catalogue-focus-${node.focus} `}
        onClick={() => {
          recursiveToggleExpand(node, items)
          !node.children && nodeToAnchor(node, nodeTree)
          setCatalogueNodeTree([...nodeTree])
        }}
      >
        <div className={`catalogue-${node.level}`}>
          <div className="catalogue-indent">
            <Icon
              name={"arrow_drop_down_black_24dp"}
              className={`catalogue-icon-${Boolean(node.children)}`}
            />
            <span
              onClick={e => {
                e.stopPropagation()
                nodeToAnchor(node, nodeTree)
                setCatalogueNodeTree([...nodeTree])
              }}
            >
              {node.text}
            </span>
          </div>
        </div>
      </div>
      {node.children && (
        <div
          key={node.anchor + node.level}
          className={`catalogue-children catalogue-expand-${node.expand}`}
        >
          {renderOneNode(node.children, nodeTree, setCatalogueNodeTree)}
        </div>
      )}
    </React.Fragment>
  ))
}
