"use client";

import { useCallback, useMemo, type Key } from "react";
import { Spin, Tree } from "antd";
import type { TreeProps } from "antd";
import { FolderOutlined } from "@ant-design/icons";

import { useI18n } from "@/i18n";
import { getUserFileFolderKey, type UserFileItem } from "@/utils/userFileLibrary";

interface AssetLibraryFolderTreeProps {
  folders: UserFileItem[];
  childrenByFolderId: Record<number, UserFileItem[]>;
  loadingFolderIds: Set<number>;
  loadedFolderIds: Set<number>;
  expandedKeys: Key[];
  selectedFolderId: number | null;
  disabledFolderIds?: Set<number>;
  onExpandedKeysChange: (keys: Key[]) => void;
  onSelectFolder: (folderId: number) => void;
  onLoadFolderChildren: (folderId: number) => void | Promise<void>;
}

type FolderTreeNode = {
  key: string;
  title: string;
  item?: UserFileItem;
  isLeaf: boolean;
  depth: number;
  isEmpty?: boolean;
  children?: FolderTreeNode[];
};

const folderTreeClassName = [
  "!bg-transparent !text-[var(--text-secondary)]",
  "[&_.ant-tree-list-holder-inner]:gap-y-1",
  "[&_.ant-tree-treenode]:!w-full [&_.ant-tree-treenode]:!items-center [&_.ant-tree-treenode]:!p-0",
  "[&_.ant-tree-indent-unit]:!w-5",
  "[&_.ant-tree-switcher]:!hidden",
  "[&_.ant-tree-node-content-wrapper]:!m-0 [&_.ant-tree-node-content-wrapper]:!min-w-0 [&_.ant-tree-node-content-wrapper]:!flex-1 [&_.ant-tree-node-content-wrapper]:!bg-transparent [&_.ant-tree-node-content-wrapper]:!p-0 [&_.ant-tree-node-content-wrapper]:!text-inherit",
  "[&_.ant-tree-node-content-wrapper:hover]:!bg-transparent [&_.ant-tree-node-content-wrapper.ant-tree-node-selected]:!bg-transparent",
  "[&_.ant-tree-title]:!block [&_.ant-tree-title]:!w-full",
].join(" ");

export function AssetLibraryFolderTree({
  folders,
  childrenByFolderId,
  loadingFolderIds,
  loadedFolderIds,
  expandedKeys,
  selectedFolderId,
  disabledFolderIds,
  onExpandedKeysChange,
  onSelectFolder,
  onLoadFolderChildren,
}: AssetLibraryFolderTreeProps) {
  const { t } = useI18n();

  const treeData = useMemo<FolderTreeNode[]>(() => {
    const buildNodes = (items: UserFileItem[], depth: number): FolderTreeNode[] => (
      items
        .filter((item) => item.nodeType === "folder")
        .map((folder) => {
          const folderKey = getUserFileFolderKey(folder.id);
          const rawChildren = childrenByFolderId[folder.id] || [];
          const childFolders = buildNodes(rawChildren, depth + 1);
          const isLoadedEmpty = loadedFolderIds.has(folder.id)
            && !loadingFolderIds.has(folder.id)
            && childFolders.length === 0;

          return {
            key: folderKey,
            title: folder.name,
            item: folder,
            isLeaf: false,
            depth,
            children: isLoadedEmpty
              ? [{
                  key: `${folderKey}-empty`,
                  title: "",
                  isLeaf: true,
                  depth: depth + 1,
                  isEmpty: true,
                }]
              : childFolders,
          };
        })
    );

    return buildNodes(folders, 0);
  }, [childrenByFolderId, folders, loadedFolderIds, loadingFolderIds]);

  const handleExpand = useCallback<NonNullable<TreeProps<FolderTreeNode>["onExpand"]>>((keys, info) => {
    onExpandedKeysChange(keys);
    if (info.expanded && info.node.item) {
      void onLoadFolderChildren(info.node.item.id);
    }
  }, [onExpandedKeysChange, onLoadFolderChildren]);

  const titleRender = useCallback((node: FolderTreeNode) => {
    if (node.isEmpty) {
      return (
        <div className="flex h-8 items-center px-3 text-xs text-[var(--text-disabled)]">
          {t("assetLibrary.folderEmpty")}
        </div>
      );
    }

    const item = node.item;
    if (!item) return null;

    const isSelected = selectedFolderId === item.id;
    const isLoading = loadingFolderIds.has(item.id);
    const isExpanded = expandedKeys.includes(node.key);
    const isDisabled = disabledFolderIds?.has(item.id) ?? false;
    return (
      <button
        type="button"
        disabled={isDisabled}
        className={`flex h-10 w-full items-center gap-3 rounded-lg px-3 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-40 ${
          isSelected
            ? "bg-[var(--surface-active)] text-[var(--text-primary)]"
            : "text-[var(--text-secondary)] hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)]"
        }`}
        onClick={() => {
          onSelectFolder(item.id);
          onExpandedKeysChange(
            isExpanded
              ? expandedKeys.filter((key) => key !== node.key)
              : [...expandedKeys, node.key]
          );
          if (!isExpanded) {
            void onLoadFolderChildren(item.id);
          }
        }}
      >
        <FolderOutlined className="shrink-0 text-[15px] text-[var(--text-muted)]" />
        <span className="min-w-0 flex-1 truncate">{item.name}</span>
        {isLoading && <Spin size="small" />}
      </button>
    );
  }, [
    expandedKeys,
    disabledFolderIds,
    loadingFolderIds,
    onExpandedKeysChange,
    onLoadFolderChildren,
    onSelectFolder,
    selectedFolderId,
    t,
  ]);

  return (
    <Tree<FolderTreeNode>
      blockNode
      showIcon={false}
      showLine={false}
      className={folderTreeClassName}
      treeData={treeData}
      expandedKeys={expandedKeys}
      selectedKeys={selectedFolderId === null ? [] : [getUserFileFolderKey(selectedFolderId)]}
      onExpand={handleExpand}
      titleRender={titleRender}
    />
  );
}
