import { describe, it, expect } from 'vitest';
import { directReducer } from './reducer';
import { initialDirectMachine, type DirectEvent, type DirectMachine } from './states';
import type { StagedFile } from '../types';

const sf = (p: string): StagedFile => ({ name: p.slice(p.lastIndexOf('/') + 1), relativePath: p, size: 1 });
const run = (events: DirectEvent[]): DirectMachine => events.reduce(directReducer, initialDirectMachine);

describe('directReducer §3', () => {
  it('happy path: SelectingType -> Complete', () => {
    const m = run([
      { type: 'SELECT_TYPE', dataType: 'dicom' },
      { type: 'ADD_FILES', files: [sf('s1/i1.dcm')] },
      { type: 'START_UPLOAD' },
      { type: 'VALIDATE_OK' },
      { type: 'UPLOAD_OK' },
      { type: 'PROCESS_OK', taskIds: ['t1'] },
    ]);
    expect(m.state).toBe('Complete');
    expect(m.context.createdTaskIds).toEqual(['t1']);
  });

  it('D1: changing the data type clears staged files', () => {
    let m = run([
      { type: 'SELECT_TYPE', dataType: 'dicom' },
      { type: 'ADD_FILES', files: [sf('i1.dcm')] },
    ]);
    expect(m.context.files).toHaveLength(1);
    m = directReducer(m, { type: 'SELECT_TYPE', dataType: 'nifti' });
    expect(m.context.dataType).toBe('nifti');
    expect(m.context.files).toEqual([]);
  });

  it('D2: TOGGLE_GROUP_BY_STUDY is a no-op for 2D images, allowed for NIfTI', () => {
    const img = directReducer(
      directReducer(initialDirectMachine, { type: 'SELECT_TYPE', dataType: 'image2d' }),
      { type: 'TOGGLE_GROUP_BY_STUDY' },
    );
    expect(img.context.groupByStudy).toBe(false);

    const nii = directReducer(
      directReducer(initialDirectMachine, { type: 'SELECT_TYPE', dataType: 'nifti' }),
      { type: 'TOGGLE_GROUP_BY_STUDY' },
    );
    expect(nii.context.groupByStudy).toBe(true);
  });

  it('VALIDATE_FAIL returns to Staging carrying errors', () => {
    const m = run([
      { type: 'SELECT_TYPE', dataType: 'dicom' },
      { type: 'ADD_FILES', files: [sf('i1.dcm')] },
      { type: 'START_UPLOAD' },
      { type: 'VALIDATE_FAIL', errors: [{ code: 'UNSUPPORTED_FORMAT', message: 'x' }] },
    ]);
    expect(m.state).toBe('Staging');
    expect(m.context.errors).toHaveLength(1);
  });

  it('UPLOAD_FAIL -> UploadError -> RETRY -> Uploading', () => {
    let m = run([
      { type: 'SELECT_TYPE', dataType: 'dicom' },
      { type: 'ADD_FILES', files: [sf('i1.dcm')] },
      { type: 'START_UPLOAD' },
      { type: 'VALIDATE_OK' },
      { type: 'UPLOAD_FAIL' },
    ]);
    expect(m.state).toBe('UploadError');
    m = directReducer(m, { type: 'RETRY' });
    expect(m.state).toBe('Uploading');
  });

  it('ignores illegal events (PROCESS_OK while Staging) as a no-op', () => {
    const staged = run([
      { type: 'SELECT_TYPE', dataType: 'dicom' },
      { type: 'ADD_FILES', files: [sf('i1.dcm')] },
    ]);
    const after = directReducer(staged, { type: 'PROCESS_OK', taskIds: ['x'] });
    expect(after).toBe(staged); // unchanged reference
  });
});
