/**
 * Folder tree for a dataset's working files (Option B — real folders inside a dataset).
 *
 * Builds an expandable folder hierarchy from each file's folderPath (migration 026), and nests
 * segmentation masks under the image they segment (parentFileId / migration 018) so a scan and its
 * organ masks read as one entry. Pure + structural so it is unit-testable without the API client.
 */

/** The structural slice of an ImagehubFile this builder needs (ImagehubFile satisfies it). */
export type TreeFileInput = {
  id: string;
  logicalPath: string;
  folderPath: string;
  fileKind: 'image' | 'segmentation';
  parentFileId?: string | null;
  size: number;
  mediaType: string;
  organLabel: string;
};

export type TreeFile = {
  kind: 'file';
  id: string;
  name: string;
  fileKind: 'image' | 'segmentation';
  size: number;
  mediaType: string;
  organLabel: string;
  /** Segmentation masks linked to this image via parentFileId, nested beneath it. */
  masks: TreeFile[];
};

export type TreeFolder = {
  kind: 'folder';
  name: string;
  path: string;
  folders: TreeFolder[];
  files: TreeFile[];
  /** Recursive count of top-level entries (images + orphan masks); nested masks are not counted. */
  fileCount: number;
};

function segments(path: string): string[] {
  return path.split('/').map((s) => s.trim()).filter(Boolean);
}

export function buildFolderTree(files: TreeFileInput[]): TreeFolder {
  const byId = new Map(files.map((f) => [f.id, f]));
  const masksByParent = new Map<string, TreeFileInput[]>();
  const nested = new Set<string>();
  for (const f of files) {
    if (f.fileKind === 'segmentation' && f.parentFileId && byId.has(f.parentFileId)) {
      const arr = masksByParent.get(f.parentFileId) ?? [];
      arr.push(f);
      masksByParent.set(f.parentFileId, arr);
      nested.add(f.id);
    }
  }

  const root: TreeFolder = { kind: 'folder', name: '', path: '', folders: [], files: [], fileCount: 0 };
  const folderAt = (path: string): TreeFolder => {
    let cur = root;
    let acc = '';
    for (const seg of segments(path)) {
      acc = acc ? `${acc}/${seg}` : seg;
      let next = cur.folders.find((x) => x.name === seg);
      if (!next) {
        next = { kind: 'folder', name: seg, path: acc, folders: [], files: [], fileCount: 0 };
        cur.folders.push(next);
      }
      cur = next;
    }
    return cur;
  };

  const toFile = (f: TreeFileInput): TreeFile => ({
    kind: 'file',
    id: f.id,
    name: f.logicalPath,
    fileKind: f.fileKind,
    size: f.size,
    mediaType: f.mediaType,
    organLabel: f.organLabel,
    masks: (masksByParent.get(f.id) ?? [])
      .slice()
      .sort((a, b) => a.logicalPath.localeCompare(b.logicalPath))
      .map(toFile),
  });

  for (const f of files) {
    if (nested.has(f.id)) continue;
    folderAt(f.folderPath || '').files.push(toFile(f));
  }

  const finalize = (n: TreeFolder): number => {
    n.folders.sort((a, b) => a.name.localeCompare(b.name));
    n.files.sort((a, b) => a.name.localeCompare(b.name));
    let count = n.files.length;
    for (const child of n.folders) count += finalize(child);
    n.fileCount = count;
    return count;
  };
  finalize(root);
  return root;
}
