/**
 * Pure helper that folds a flat list of changed file paths into a directory
 * tree, so the Git panel can show changes as a file tree (L8 visual). Kept free
 * of React for straightforward unit testing.
 */

import type { GitFileStatus } from "@/domain";

/** A node in the changed-files tree: a directory or a file leaf. */
export interface GitTreeNode {
  /** Last path segment (folder or file name). */
  name: string;
  /** Full repo-relative path of this node. */
  path: string;
  /** Whether this node is a directory (has children) or a file leaf. */
  isDir: boolean;
  /** For file leaves: whether the change is staged. */
  staged: boolean;
  /** Child nodes (empty for files). */
  children: GitTreeNode[];
}

/**
 * Builds the directory tree for a set of changed files. Directories come before
 * files at each level, both alphabetically sorted.
 */
export function buildFileTree(files: GitFileStatus[]): GitTreeNode[] {
  const root: GitTreeNode = {
    name: "",
    path: "",
    isDir: true,
    staged: false,
    children: [],
  };

  for (const file of files) {
    const parts = file.path.split("/").filter(Boolean);
    let node = root;
    parts.forEach((part, i) => {
      const isLeaf = i === parts.length - 1;
      const path = parts.slice(0, i + 1).join("/");
      let child = node.children.find(
        (c) => c.name === part && c.isDir === !isLeaf,
      );
      if (!child) {
        child = {
          name: part,
          path,
          isDir: !isLeaf,
          staged: file.staged,
          children: [],
        };
        node.children.push(child);
      }
      node = child;
    });
  }

  sort(root);
  return root.children;
}

function sort(node: GitTreeNode): void {
  node.children.sort((a, b) => {
    if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
    return a.name.localeCompare(b.name);
  });
  node.children.forEach(sort);
}
