import type { FolderTreeNode } from "@/lib/sidebar-nav-maps"

/** Slug URL-safe pour un segment de chemin (dossier / partie de libellé). */
export function slugifyNavSegment(name: string): string {
  const s = name
    .trim()
    .toLowerCase()
    .normalize("NFD")
    .replace(/\p{M}/gu, "")
    .replace(/[^a-z0-9]+/g, "-")
    .replace(/^-|-$/g, "")
  return s || "dossier"
}

export function folderIdFromPathSlugs(slugs: string[]): string {
  return `folder-${slugs.join("-")}`
}

export function findFolderPath(
  nodes: FolderTreeNode[],
  id: string,
  acc: FolderTreeNode[] = []
): FolderTreeNode[] | null {
  for (const n of nodes) {
    const next = [...acc, n]
    if (n.id === id) return next
    if (n.children?.length) {
      const hit = findFolderPath(n.children, id, next)
      if (hit) return hit
    }
  }
  return null
}

export function collectFolderIdsInTree(nodes: FolderTreeNode[]): string[] {
  const out: string[] = []
  const walk = (ns: FolderTreeNode[]) => {
    for (const e of ns) {
      out.push(e.id)
      if (e.children?.length) walk(e.children)
    }
  }
  walk(nodes)
  return out
}

function collectSubtreeIdsFromNode(node: FolderTreeNode): Set<string> {
  const s = new Set<string>([node.id])
  if (node.children?.length) {
    for (const c of node.children) {
      for (const x of collectSubtreeIdsFromNode(c)) s.add(x)
    }
  }
  return s
}

export function uniqueFolderPathId(
  pathSlugs: string[],
  usedIds: Set<string>
): string {
  let base = folderIdFromPathSlugs(pathSlugs)
  if (!usedIds.has(base)) return base
  let n = 2
  while (usedIds.has(`${base}-${n}`)) n += 1
  return `${base}-${n}`
}

/** Slugs des ancêtres (noms affichés) pour un parent `parentId` dans l’arbre. */
export function ancestorLabelSlugsForParentId(
  tree: FolderTreeNode[],
  parentId: string | null
): string[] {
  if (parentId === null) return []
  const path = findFolderPath(tree, parentId)
  if (!path) return []
  return path.map((n) => slugifyNavSegment(n.label))
}

export function proposeNewFolderId(
  tree: FolderTreeNode[],
  labelRowIds: readonly string[],
  parentId: string | null,
  displayLabel: string
): string {
  const used = new Set<string>([
    ...collectFolderIdsInTree(tree),
    ...labelRowIds,
  ])
  const anc = ancestorLabelSlugsForParentId(tree, parentId)
  const leaf = slugifyNavSegment(displayLabel)
  return uniqueFolderPathId([...anc, leaf], used)
}

/**
 * Recalcule les ids du sous-arbre enraciné à `rootId` (chemins slug à partir des libellés).
 * `tree` doit déjà contenir les bons libellés pour ce sous-arbre.
 */
export function rekeyFolderSubtreeAt(
  tree: FolderTreeNode[],
  rootId: string,
  labelRowIds: readonly string[]
): { tree: FolderTreeNode[]; idMap: Record<string, string> } | null {
  const path = findFolderPath(tree, rootId)
  if (!path) return null
  const rootNode = path[path.length - 1]!
  const ancestorSlugs = path.slice(0, -1).map((n) => slugifyNavSegment(n.label))

  const subtreeOldIds = collectSubtreeIdsFromNode(rootNode)
  const used = new Set<string>([...labelRowIds])
  for (const id of collectFolderIdsInTree(tree)) {
    if (!subtreeOldIds.has(id)) used.add(id)
  }

  const idMap: Record<string, string> = {}

  function rebuild(node: FolderTreeNode, anc: string[]): FolderTreeNode {
    const pathSlugs = [...anc, slugifyNavSegment(node.label)]
    const newId = uniqueFolderPathId(pathSlugs, used)
    used.add(newId)
    if (newId !== node.id) idMap[node.id] = newId
    const kids = node.children?.length
      ? node.children.map((c) => rebuild(c, pathSlugs))
      : undefined
    return { ...node, id: newId, children: kids }
  }

  const rebuiltRoot = rebuild(rootNode, ancestorSlugs)

  function replaceAt(nodes: FolderTreeNode[]): FolderTreeNode[] {
    return nodes.map((n) => {
      if (n.id === rootId) return rebuiltRoot
      if (n.children?.length) return { ...n, children: replaceAt(n.children) }
      return n
    })
  }

  return { tree: replaceAt(tree), idMap }
}
