/* eslint-disable @typescript-eslint/ban-ts-comment */
// @ts-nocheck

import {
  getFolderIdFromNodeId,
  getItemIdFromNodeId,
} from "./panelFolders";
import {
  menuItem,
  menuLabel,
  openContextMenuAtPoint,
} from "./contextMenuSchema";

function clearDropClasses(container) {
  if (!container) {
    return;
  }
  container.querySelectorAll(".folder-drop-before, .folder-drop-after, .folder-drop-inside, .folder-root-drop-active")
    .forEach((node) => {
      node.classList.remove("folder-drop-before", "folder-drop-after", "folder-drop-inside", "folder-root-drop-active");
    });
}

function beginRowDrag(scope, panelKey, dragDescriptor, handle, container, event) {
  if (!dragDescriptor || !dragDescriptor.kind || !dragDescriptor.id) {
    event.preventDefault();
    return;
  }
  scope.organizedListDrag = {
    panelKey,
    kind: dragDescriptor.kind,
    id: String(dragDescriptor.id || ""),
  };
  if (event.dataTransfer) {
    event.dataTransfer.effectAllowed = "copyMove";
    event.dataTransfer.setData("text/plain", JSON.stringify(scope.organizedListDrag));
  }
  handle.classList.add("dragging");
  container.classList.add("folder-list-dragging");
}

function finishRowDrag(scope, handle, container) {
  scope.organizedListDrag = null;
  if (handle) {
    handle.classList.remove("dragging");
  }
  if (container) {
    container.classList.remove("folder-list-dragging");
    clearDropClasses(container);
  }
}

function bindDragHandle(scope, panelKey, container, row, dragDescriptor) {
  const header = row.querySelector(".npc-row-header") || row.querySelector(".folder-row-header") || row;
  const handle = document.createElement("button");
  handle.type = "button";
  handle.className = "selector-drag-handle";
  handle.title = "Drag to reorder";
  handle.setAttribute("aria-label", handle.title);
  handle.innerHTML = '<span class="selector-drag-icon">&#8597;</span>';
  handle.setAttribute("draggable", "true");
  handle.addEventListener("click", (event) => {
    event.preventDefault();
    event.stopPropagation();
  });
  handle.addEventListener("dragstart", (event) => {
    event.stopPropagation();
    beginRowDrag(scope, panelKey, dragDescriptor, handle, container, event);
  });
  handle.addEventListener("dragend", () => {
    finishRowDrag(scope, handle, container);
  });
  header.insertBefore(handle, header.firstChild);
}

function bindDropTarget(scope, panelKey, container, targetEl, resolveDropInfo, onMove) {
  if (!targetEl) {
    return;
  }

  targetEl.addEventListener("dragover", (event) => {
    const dragging = scope.organizedListDrag;
    if (!dragging || dragging.panelKey !== panelKey) {
      return;
    }
    const dropInfo = resolveDropInfo(event, dragging);
    if (!dropInfo) {
      return;
    }
    event.preventDefault();
    if (event.dataTransfer) {
      event.dataTransfer.dropEffect = "move";
    }
    clearDropClasses(container);
    if (dropInfo.kind === "root") {
      targetEl.classList.add("folder-root-drop-active");
    } else if (dropInfo.position === "inside") {
      targetEl.classList.add("folder-drop-inside");
    } else if (dropInfo.position === "after") {
      targetEl.classList.add("folder-drop-after");
    } else {
      targetEl.classList.add("folder-drop-before");
    }
  });

  targetEl.addEventListener("drop", (event) => {
    const dragging = scope.organizedListDrag;
    if (!dragging || dragging.panelKey !== panelKey) {
      return;
    }
    const dropInfo = resolveDropInfo(event, dragging);
    if (!dropInfo) {
      return;
    }
    event.preventDefault();
    clearDropClasses(container);
    onMove(dragging, dropInfo);
  });
}

function openFolderContextMenu(scope, event, options) {
  const {
    panelKey,
    folder,
    folderId,
    onToggleFolder,
    onRenameFolder,
    onDeleteFolder,
  } = options || {};
  if (!scope?.atTooltip || !event || !folderId) {
    return false;
  }
  event.preventDefault();
  event.stopPropagation();
  return openContextMenuAtPoint(scope.atTooltip, event.clientX, event.clientY, [
    menuLabel(folder?.name || "New Folder"),
    menuItem("<span>" + (folder?.collapsed ? "Expand folder" : "Collapse folder") + "</span>", () => {
      onToggleFolder?.(folderId);
      scope.atTooltip.close();
    }),
    menuItem("<span>Rename folder</span>", () => {
      onRenameFolder?.(folderId);
      scope.atTooltip.close();
    }),
    menuItem("<span>Delete folder</span>", () => {
      onDeleteFolder?.(folderId);
      scope.atTooltip.close();
    }),
  ], String(panelKey || "") + ":folder:" + String(folderId || ""));
}

export function renderFolderedSelectorList(options) {
  const {
    scope,
    container,
    panelKey,
    items,
    getItemId,
    renderItemRow,
    emptyMessage,
    baseLabel,
    onMove,
    onToggleFolder,
    onRenameFolder,
    onDeleteFolder,
  } = options;
  if (!container) {
    return;
  }

  const validItems = Array.isArray(items) ? items.slice() : [];
  const itemById = new Map();
  const itemIds = validItems
    .map((entry) => {
      const itemId = String(getItemId(entry) || "").trim();
      if (!itemId) {
        return "";
      }
      itemById.set(itemId, entry);
      return itemId;
    })
    .filter(Boolean);
  const layout = scope.getPanelLayout(panelKey, itemIds);
  container.innerHTML = "";

  const root = document.createElement("div");
  root.className = "folder-list-root";
  container.appendChild(root);

  const appendFolderNode = (folderId) => {
    const folder = layout.folders[folderId];
    if (!folder) {
      return;
    }
    const folderWrap = document.createElement("div");
    folderWrap.className = "folder-block" + (folder.collapsed ? " collapsed" : "");

    const folderHeader = document.createElement("div");
    folderHeader.className = "history-row npc-row folder-row";
    const headerInner = document.createElement("div");
    headerInner.className = "folder-row-header";
    const toggleBtn = document.createElement("button");
    toggleBtn.type = "button";
    toggleBtn.className = "folder-toggle-btn";
    toggleBtn.innerHTML = '<span class="folder-toggle-icon">' + (folder.collapsed ? "&#9656;" : "&#9662;") + "</span>";
    toggleBtn.title = folder.collapsed ? "Expand folder" : "Collapse folder";
    toggleBtn.setAttribute("aria-label", toggleBtn.title);
    toggleBtn.addEventListener("click", (event) => {
      event.preventDefault();
      event.stopPropagation();
      onToggleFolder(folderId);
    });
    headerInner.appendChild(toggleBtn);

    const folderIcon = document.createElement("span");
    folderIcon.className = "folder-row-icon";
    folderIcon.innerHTML = "&#128193;";
    headerInner.appendChild(folderIcon);

    const titleWrap = document.createElement("div");
    titleWrap.className = "folder-row-copy";
    titleWrap.innerHTML =
      "<span>" + scope.runtimeEscapeHtml(folder.name || "New Folder") + "</span>" +
      '<span class="history-meta">' + String(folder.itemOrder.length) + " item" + (folder.itemOrder.length === 1 ? "" : "s") + "</span>";
    headerInner.appendChild(titleWrap);
    folderHeader.appendChild(headerInner);
    folderHeader.addEventListener("click", () => onToggleFolder(folderId));
    folderHeader.addEventListener("contextmenu", (event) => {
      openFolderContextMenu(scope, event, {
        panelKey,
        folder,
        folderId,
        onToggleFolder,
        onRenameFolder,
        onDeleteFolder,
      });
    });
    bindDragHandle(scope, panelKey, root, folderHeader, { kind: "folder", id: folderId });
    bindDropTarget(scope, panelKey, root, folderHeader, (event, dragging) => {
      if (dragging.kind === "item") {
        return { kind: "folder", id: folderId, position: "inside" };
      }
      if (dragging.kind === "folder") {
        const rect = folderHeader.getBoundingClientRect();
        return {
          kind: "folder",
          id: folderId,
          position: event.clientY < rect.top + (rect.height / 2) ? "before" : "after",
        };
      }
      return null;
    }, onMove);
    folderWrap.appendChild(folderHeader);

    const folderBody = document.createElement("div");
    folderBody.className = "folder-children";
    bindDropTarget(scope, panelKey, root, folderBody, (_event, dragging) => {
      if (dragging.kind !== "item") {
        return null;
      }
      return { kind: "folder", id: folderId, position: "inside" };
    }, onMove);
    if (!folder.collapsed) {
      folder.itemOrder.forEach((itemId) => {
        const item = itemById.get(itemId);
        if (!item) {
          return;
        }
        const row = renderItemRow(item, { parentFolderId: folderId });
        bindDragHandle(scope, panelKey, root, row, { kind: "item", id: itemId, parentFolderId: folderId });
        bindDropTarget(scope, panelKey, root, row, (event, dragging) => {
          if (dragging.kind === "folder") {
            return null;
          }
          const rect = row.getBoundingClientRect();
          return {
            kind: "item",
            id: itemId,
            parentFolderId: folderId,
            position: event.clientY < rect.top + (rect.height / 2) ? "before" : "after",
          };
        }, onMove);
        folderBody.appendChild(row);
      });
      if (folder.itemOrder.length === 0) {
        const emptyFolder = document.createElement("div");
        emptyFolder.className = "folder-empty";
        emptyFolder.textContent = "Drop selectors here";
        folderBody.appendChild(emptyFolder);
      }
    }
    folderWrap.appendChild(folderBody);
    root.appendChild(folderWrap);
  };

  layout.rootOrder.forEach((nodeId) => {
    const folderId = getFolderIdFromNodeId(nodeId);
    if (folderId) {
      appendFolderNode(folderId);
      return;
    }
    const itemId = getItemIdFromNodeId(nodeId);
    const item = itemById.get(itemId);
    if (!item) {
      return;
    }
    const row = renderItemRow(item, { parentFolderId: "" });
    bindDragHandle(scope, panelKey, root, row, { kind: "item", id: itemId, parentFolderId: "" });
    bindDropTarget(scope, panelKey, root, row, (event, dragging) => {
      if (dragging.kind === "folder") {
        const rect = row.getBoundingClientRect();
        return {
          kind: "item",
          id: itemId,
          parentFolderId: "",
          position: event.clientY < rect.top + (rect.height / 2) ? "before" : "after",
        };
      }
      const rect = row.getBoundingClientRect();
      return {
        kind: "item",
        id: itemId,
        parentFolderId: "",
        position: event.clientY < rect.top + (rect.height / 2) ? "before" : "after",
      };
    }, onMove);
    root.appendChild(row);
  });

  const hasRootNodes = layout.rootOrder.length > 0;
  if (!hasRootNodes && emptyMessage) {
    const empty = document.createElement("p");
    empty.className = "muted folder-list-empty";
    empty.textContent = emptyMessage;
    root.appendChild(empty);
  }

  if (hasRootNodes) {
    const baseDropZone = document.createElement("div");
    baseDropZone.className = "folder-root-drop-zone";
    baseDropZone.textContent = baseLabel || "Base Panel";
    bindDropTarget(scope, panelKey, root, baseDropZone, (_event, dragging) => {
      if (!dragging || !dragging.kind) {
        return null;
      }
      return {
        kind: "root",
        id: "",
        position: "inside",
      };
    }, onMove);
    root.appendChild(baseDropZone);
  }
}
