import * as React from "react";
import { HTMLProps, useRef } from "react";
import { TreeItemChildren } from "../treeItem/TreeItemChildren";
import { useFocusWithin } from "./useFocusWithin";
import { useTreeKeyboardBindings } from "./useTreeKeyboardBindings";
import { SearchInput } from "../search/SearchInput";
import { useTree } from "./Tree";
import { useTreeEnvironment } from "../controlledEnvironment/ControlledTreeEnvironment";
import { useDragAndDrop } from "../controlledEnvironment/DragAndDropProvider";
import { MaybeLiveDescription } from "./MaybeLiveDescription";

const treeContainerStyle: React.CSSProperties = {
  position: "relative",
};

export const TreeManager = (): JSX.Element => {
  const { treeId, rootItem, renderers, treeInformation } = useTree();
  const { setActiveTree, items, canSearch } = useTreeEnvironment();
  const containerRef = useRef<HTMLElement>(null);
  const { abortProgrammaticDrag, onDragLeaveTreeHandler } = useDragAndDrop();

  useTreeKeyboardBindings();

  useFocusWithin(
    containerRef.current,
    () => {
      setActiveTree(treeId);
    },
    () => {
      setActiveTree((oldTreeId) => (oldTreeId === treeId ? undefined : oldTreeId));
    }
  );

  const rootChildren = items[rootItem].children;

  const treeChildren = (
    <>
      <MaybeLiveDescription />
      <TreeItemChildren depth={0} parentId={items[rootItem].index}>
        {rootChildren ?? []}
      </TreeItemChildren>
      {canSearch && <SearchInput containerRef={containerRef.current} />}
    </>
  );

  const containerProps: HTMLProps<HTMLElement> = {
    onDragLeave: onDragLeaveTreeHandler,
    onMouseDown: abortProgrammaticDrag,
    ref: containerRef,
    style: treeContainerStyle,
    role: "tree",
    "aria-label": !treeInformation.treeLabelledBy ? treeInformation.treeLabel : undefined,
    "aria-labelledby": treeInformation.treeLabelledBy,
    // @ts-expect-error non-standard attribute.
    "data-rct-tree": treeId,
  };

  return renderers.renderTreeContainer({
    children: treeChildren,
    info: treeInformation,
    containerProps,
  }) as JSX.Element;
};
