// Data-import DOMAIN — Direct Upload reducer (pure transition function). Source: §3:83-93.
// Illegal (state, event) pairs are no-ops (return the machine unchanged) — safe for a UI-driven
// machine. All side effects (validate, upload, process) are performed by the application use-case,
// which feeds VALIDATE_OK/FAIL, UPLOAD_PROGRESS/OK/FAIL, PROCESS_OK/FAIL back in.

import { canToggleGroupByStudy } from './guards';
import type { DirectEvent, DirectMachine } from './states';

const PRE_UPLOAD: ReadonlySet<string> = new Set(['SelectingType', 'ConfiguringStructure', 'Staging']);

export function directReducer(m: DirectMachine, e: DirectEvent): DirectMachine {
  const { state, context } = m;

  switch (e.type) {
    case 'SELECT_TYPE': {
      if (!PRE_UPLOAD.has(state)) return m; // D1 — can't change type mid-upload
      const changed = e.dataType !== context.dataType;
      return {
        state: 'ConfiguringStructure',
        // Changing the type discards files/group-by-study staged for the old type.
        context: changed
          ? { ...context, dataType: e.dataType, groupByStudy: false, files: [], errors: [] }
          : { ...context, dataType: e.dataType },
      };
    }

    case 'TOGGLE_GROUP_BY_STUDY': {
      if (state !== 'ConfiguringStructure' && state !== 'Staging') return m;
      if (!canToggleGroupByStudy(context)) return m; // D2 — no-op for 2D/video
      return { ...m, context: { ...context, groupByStudy: !context.groupByStudy } };
    }

    case 'ADD_FILES': {
      if (state !== 'ConfiguringStructure' && state !== 'Staging') return m;
      return { state: 'Staging', context: { ...context, files: [...context.files, ...e.files], errors: [] } };
    }

    case 'CLEAR_FILES': {
      if (state !== 'Staging' && state !== 'ConfiguringStructure') return m;
      return { state: 'Staging', context: { ...context, files: [], errors: [] } };
    }

    case 'START_UPLOAD':
      if (state !== 'Staging') return m;
      return { ...m, state: 'Validating' };

    case 'VALIDATE_OK':
      if (state !== 'Validating') return m;
      return { state: 'Uploading', context: { ...context, progress: 0, errors: [] } };

    case 'VALIDATE_FAIL':
      if (state !== 'Validating') return m;
      return { state: 'Staging', context: { ...context, errors: e.errors } };

    case 'UPLOAD_PROGRESS':
      if (state !== 'Uploading') return m;
      return { ...m, context: { ...context, progress: clamp(e.progress) } };

    case 'UPLOAD_OK':
      if (state !== 'Uploading') return m;
      return { state: 'Processing', context: { ...context, progress: 100 } };

    case 'UPLOAD_FAIL':
      if (state !== 'Uploading') return m;
      return { state: 'UploadError', context: { ...context, errors: e.errors ?? context.errors } };

    case 'PROCESS_OK':
      if (state !== 'Processing') return m;
      return { state: 'Complete', context: { ...context, createdTaskIds: e.taskIds, errors: [] } };

    case 'PROCESS_FAIL':
      if (state !== 'Processing') return m;
      return { state: 'PartialFailure', context: { ...context, errors: e.errors ?? context.errors } };

    case 'RETRY':
      if (state === 'UploadError') return { ...m, state: 'Uploading', context: { ...context, progress: 0 } };
      if (state === 'PartialFailure') return { ...m, state: 'Processing' };
      return m;

    default:
      return m;
  }
}

function clamp(n: number): number {
  return Math.max(0, Math.min(100, n));
}
