import {
  map, reduce, sort, range, omit, times
} from 'rambda';
import type { JobId } from '../../types';
import { updateCTime } from '../johnson';
import { fillCorrupted } from '../campbel';

type JobOperations = {
  jobId: JobId,
  operations: Array<{ t: number }>
};

type JobOperationsWithC = {
  jobId: JobId,
  operations: Array<{ t: number, c: number }>
};

export const createSchedule = (jobsOperations: JobOperations[], processorsCount: number): JobOperationsWithC[] => {
  jobsOperations = fillCorrupted(jobsOperations);

  const jobsOperationsWithKoefs = map(jobsOperation => {
    const koef = reduce(
      (acc, i) => acc + Math.abs(processorsCount - 2 * i + 1) * jobsOperation.operations[i-1].t,
      0,
      range(1, processorsCount + 1)
    );

    return { ...jobsOperation, koef };
  }, jobsOperations);

  let sortedJobsOperations = sort(
    (a: JobOperations, b: JobOperations) => {
      return b.koef - a.koef;
    },
    jobsOperationsWithKoefs
  );

  sortedJobsOperations = map(omit('koef'), sortedJobsOperations);

  return updateCTime(sortedJobsOperations, processorsCount);
};

export default (jobsOperations: JobOperations[], processorsCount: number) => {
  const schedule = createSchedule(jobsOperations, processorsCount);

  return times(i =>
    map((jobTime: JobOperationsWithC) => ({
      processor: i + 1,
      startTime: jobTime.operations[i].c - jobTime.operations[i].t,
      endTime: jobTime.operations[i].c,
    }), schedule)
  , processorsCount);
};