import { Folder, FolderOpen } from "lucide-react";
import type { CSSProperties, DragEvent as ReactDragEvent, MouseEvent as ReactMouseEvent, ReactNode } from "react";
import { i18nMessage } from "../i18n/LanguageContext";

export type ExplorerTreeNodeContext = {
  depth: number;
  active: boolean;
  expanded: boolean;
  hasChildren: boolean;
  disabled: boolean;
};

export type ExplorerTreeProps<T> = {
  nodes: T[];
  getNodeId: (node: T) => string;
  getNodeLabel: (node: T) => string;
  getNodeChildren: (node: T) => T[];
  activeId?: string;
  expandedIds: Set<string>;
  onOpen: (node: T, context: ExplorerTreeNodeContext) => void;
  onToggle: (node: T, context: ExplorerTreeNodeContext) => void;
  disabled?: boolean;
  depth?: number;
  className?: string;
  childrenBaseClassName?: string;
  nodeContainerClassName?: string;
  nodeWrapBaseClassName?: string;
  toggleBaseClassName?: string;
  nodeButtonBaseClassName?: string;
  renderToggleIcon?: (node: T, context: ExplorerTreeNodeContext) => ReactNode;
  renderNodeContent?: (node: T, context: ExplorerTreeNodeContext) => ReactNode;
  getNodeWrapClassName?: (node: T, context: ExplorerTreeNodeContext) => string | undefined;
  getNodeWrapStyle?: (node: T, context: ExplorerTreeNodeContext) => CSSProperties | undefined;
  getNodeButtonClassName?: (node: T, context: ExplorerTreeNodeContext) => string | undefined;
  getNodeDraggable?: (node: T, context: ExplorerTreeNodeContext) => boolean;
  onContextMenu?: (event: ReactMouseEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
  onDragStart?: (event: ReactDragEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
  onDragEnd?: (event: ReactDragEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
  onDragOver?: (event: ReactDragEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
  onDragLeave?: (event: ReactDragEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
  onDrop?: (event: ReactDragEvent<HTMLElement>, node: T, context: ExplorerTreeNodeContext) => void;
};

export default function ExplorerTree<T>({
  nodes,
  getNodeId,
  getNodeLabel,
  getNodeChildren,
  activeId = "",
  expandedIds,
  onOpen,
  onToggle,
  disabled = false,
  depth = 1,
  className = "",
  childrenBaseClassName = "explorer-tree-children file-tree-children",
  nodeContainerClassName = "",
  nodeWrapBaseClassName = "explorer-tree-node-wrap file-tree-node-wrap",
  toggleBaseClassName = "explorer-tree-toggle file-tree-toggle",
  nodeButtonBaseClassName = "explorer-tree-node file-tree-node",
  renderToggleIcon,
  renderNodeContent,
  getNodeWrapClassName,
  getNodeWrapStyle,
  getNodeButtonClassName,
  getNodeDraggable,
  onContextMenu,
  onDragStart,
  onDragEnd,
  onDragOver,
  onDragLeave,
  onDrop
}: ExplorerTreeProps<T>) {
  if (nodes.length === 0) return null;

  return (
    <div className={[childrenBaseClassName, className].filter(Boolean).join(" ")}>
      {nodes.map((node) => {
        const nodeId = getNodeId(node);
        const children = getNodeChildren(node);
        const hasChildren = children.length > 0;
        const expanded = expandedIds.has(nodeId);
        const active = activeId === nodeId;
        const context: ExplorerTreeNodeContext = { depth, active, expanded, hasChildren, disabled };
        const draggable = getNodeDraggable?.(node, context) ?? false;

        return (
          <div key={nodeId} className={nodeContainerClassName}>
            <div
              className={[
              nodeWrapBaseClassName,
              active ? "is-active" : "",
              getNodeWrapClassName?.(node, context) ?? ""].
              filter(Boolean).join(" ")}
              style={getNodeWrapStyle?.(node, context) ?? { paddingLeft: `${Math.min(depth * 14, 56)}px` }}
              draggable={draggable && !disabled}
              onContextMenu={onContextMenu ? (event) => onContextMenu(event, node, context) : undefined}
              onDragStart={draggable && onDragStart ? (event) => onDragStart(event, node, context) : undefined}
              onDragEnd={draggable && onDragEnd ? (event) => onDragEnd(event, node, context) : undefined}
              onDragOver={onDragOver ? (event) => onDragOver(event, node, context) : undefined}
              onDragLeave={onDragLeave ? (event) => onDragLeave(event, node, context) : undefined}
              onDrop={onDrop ? (event) => onDrop(event, node, context) : undefined}>
              
              <button
                type="button"
                className={toggleBaseClassName}
                onClick={(event) => {
                  event.stopPropagation();
                  if (hasChildren) onToggle(node, context);
                }}
                disabled={disabled || !hasChildren}
                aria-label={i18nMessage("i18n:govoplan-core.value_value.dca59cc0", { value0: expanded ? "i18n:govoplan-core.collapse.9cf188d3" : "i18n:govoplan-core.expand.9869e506", value1: getNodeLabel(node) })}
                aria-expanded={hasChildren ? expanded : undefined}>
                
                {renderToggleIcon?.(node, context) ?? (expanded ? <FolderOpen size={15} aria-hidden="true" /> : <Folder size={15} aria-hidden="true" />)}
              </button>
              <button
                type="button"
                className={[nodeButtonBaseClassName, getNodeButtonClassName?.(node, context) ?? ""].filter(Boolean).join(" ")}
                onClick={() => onOpen(node, context)}
                disabled={disabled}>
                
                {renderNodeContent?.(node, context) ?? <span>{getNodeLabel(node)}</span>}
              </button>
            </div>
            {hasChildren && expanded &&
            <ExplorerTree
              nodes={children}
              getNodeId={getNodeId}
              getNodeLabel={getNodeLabel}
              getNodeChildren={getNodeChildren}
              activeId={activeId}
              expandedIds={expandedIds}
              onOpen={onOpen}
              onToggle={onToggle}
              disabled={disabled}
              depth={depth + 1}
              childrenBaseClassName={childrenBaseClassName}
              nodeContainerClassName={nodeContainerClassName}
              nodeWrapBaseClassName={nodeWrapBaseClassName}
              toggleBaseClassName={toggleBaseClassName}
              nodeButtonBaseClassName={nodeButtonBaseClassName}
              renderToggleIcon={renderToggleIcon}
              renderNodeContent={renderNodeContent}
              getNodeWrapClassName={getNodeWrapClassName}
              getNodeWrapStyle={getNodeWrapStyle}
              getNodeButtonClassName={getNodeButtonClassName}
              getNodeDraggable={getNodeDraggable}
              onContextMenu={onContextMenu}
              onDragStart={onDragStart}
              onDragEnd={onDragEnd}
              onDragOver={onDragOver}
              onDragLeave={onDragLeave}
              onDrop={onDrop} />

            }
          </div>);

      })}
    </div>);

}
