import { describe, it, expect } from 'vitest';
import { parseItemsList } from './parse';

describe('parseItemsList', () => {
  it('P1: malformed JSON -> single ITEMS_LIST_MALFORMED, no tasks', () => {
    const r = parseItemsList('{not json', 'dicom');
    expect(r.ok).toBe(false);
    expect(r.tasks).toEqual([]);
    expect(r.errors).toHaveLength(1);
    expect(r.errors[0].code).toBe('ITEMS_LIST_MALFORMED');
  });

  it('rejects a non-array top level', () => {
    const r = parseItemsList('{"name":"x"}', 'dicom');
    expect(r.errors[0].code).toBe('ITEMS_LIST_NOT_ARRAY');
  });

  it('accepts a valid standard DICOM list (entry = task)', () => {
    const json = JSON.stringify([
      { name: 'study-1', series: [{ items: ['bucket/s1/i1.dcm', 'bucket/s1/i2.dcm'] }] },
    ]);
    const r = parseItemsList(json, 'dicom');
    expect(r.ok).toBe(true);
    expect(r.tasks).toHaveLength(1);
    expect(r.tasks[0].name).toBe('study-1');
  });

  it('IL5: flags a missing name and a duplicate name', () => {
    const json = JSON.stringify([
      { series: [{ items: 'bucket/a.nii' }] },
      { name: 'dup', series: [{ items: 'bucket/b.nii' }] },
      { name: 'dup', series: [{ items: 'bucket/c.nii' }] },
    ]);
    const r = parseItemsList(json, 'nifti');
    expect(r.errors.map((e) => e.code)).toContain('ENTRY_NAME_MISSING');
    expect(r.errors.map((e) => e.code)).toContain('ENTRY_NAME_DUPLICATE');
  });

  it('IL3: a NIfTI series with an array items is rejected', () => {
    const json = JSON.stringify([{ name: 't', series: [{ items: ['bucket/a.nii', 'bucket/b.nii'] }] }]);
    const r = parseItemsList(json, 'nifti');
    expect(r.ok).toBe(false);
    expect(r.errors.map((e) => e.code)).toContain('ENTRY_ITEMS_SHAPE');
  });

  it('C2: a full URL in items is rejected as not bucket-relative', () => {
    const json = JSON.stringify([{ name: 't', series: [{ items: ['https://s3/bucket/a.dcm'] }] }]);
    const r = parseItemsList(json, 'dicom');
    expect(r.ok).toBe(false);
    expect(r.errors.map((e) => e.code)).toContain('PATH_NOT_BUCKET_RELATIVE');
  });

  it('accepts the simplified flat-items shape', () => {
    const json = JSON.stringify([{ name: 't', items: ['bucket/a.dcm', 'bucket/b.dcm'] }]);
    const r = parseItemsList(json, 'dicom');
    expect(r.ok).toBe(true);
    expect(r.tasks[0].items).toHaveLength(2);
  });

  it('flags an entry with neither series nor items as empty', () => {
    const json = JSON.stringify([{ name: 't' }]);
    const r = parseItemsList(json, 'dicom');
    expect(r.errors.map((e) => e.code)).toContain('ENTRY_EMPTY');
  });
});
