import { describe, it, expect } from 'vitest';

import { buildFolderTree, type TreeFileInput } from './folderTree';

const f = (over: Partial<TreeFileInput> & { id: string; logicalPath: string }): TreeFileInput => ({
  folderPath: '',
  fileKind: 'image',
  parentFileId: null,
  size: 0,
  mediaType: 'application/octet-stream',
  organLabel: '',
  ...over,
});

describe('buildFolderTree', () => {
  it('places files into folders by folderPath, loose files at root', () => {
    const tree = buildFolderTree([
      f({ id: '1', logicalPath: 'ct.nii.gz', folderPath: 'imagesTr' }),
      f({ id: '2', logicalPath: 'seg.nii.gz', folderPath: 'labelsTr' }),
      f({ id: '3', logicalPath: 'readme.txt', folderPath: '' }),
    ]);
    expect(tree.files.map((x) => x.name)).toEqual(['readme.txt']);
    expect(tree.folders.map((x) => x.name)).toEqual(['imagesTr', 'labelsTr']);
    expect(tree.folders[0].files[0].name).toBe('ct.nii.gz');
    expect(tree.fileCount).toBe(3);
  });

  it('nests segmentation masks under their parent image, not as separate entries', () => {
    const tree = buildFolderTree([
      f({ id: 'img', logicalPath: 'ct.nii.gz', folderPath: 'ca_001' }),
      f({ id: 'm1', logicalPath: 'kidney_l.nii.gz', folderPath: 'ca_001', fileKind: 'segmentation', parentFileId: 'img', organLabel: 'thận trái' }),
      f({ id: 'm2', logicalPath: 'kidney_r.nii.gz', folderPath: 'ca_001', fileKind: 'segmentation', parentFileId: 'img', organLabel: 'thận phải' }),
    ]);
    const ca = tree.folders[0];
    expect(ca.files).toHaveLength(1);
    expect(ca.files[0].masks.map((m) => m.name)).toEqual(['kidney_l.nii.gz', 'kidney_r.nii.gz']);
    expect(ca.fileCount).toBe(1);
  });

  it('treats a mask with a missing parent as a standalone file', () => {
    const tree = buildFolderTree([
      f({ id: 'm', logicalPath: 'orphan.nii.gz', fileKind: 'segmentation', parentFileId: 'gone' }),
    ]);
    expect(tree.files.map((x) => x.name)).toEqual(['orphan.nii.gz']);
    expect(tree.files[0].masks).toEqual([]);
  });

  it('builds deep folder paths and sorts siblings alphabetically', () => {
    const tree = buildFolderTree([
      f({ id: '1', logicalPath: 'b.nii.gz', folderPath: 'root/sub' }),
      f({ id: '2', logicalPath: 'a.nii.gz', folderPath: 'root/sub' }),
    ]);
    expect(tree.folders[0].path).toBe('root');
    expect(tree.folders[0].folders[0].path).toBe('root/sub');
    expect(tree.folders[0].folders[0].files.map((x) => x.name)).toEqual(['a.nii.gz', 'b.nii.gz']);
  });

  it('returns an empty root for no files', () => {
    const tree = buildFolderTree([]);
    expect(tree.fileCount).toBe(0);
    expect(tree.folders).toEqual([]);
    expect(tree.files).toEqual([]);
  });
});
