import {
  findIndex, map, propEq, reduce, filter, reverse
} from 'rambda';
import type { JobId } from '../../types';
import { max, remove } from 'ramda';
import { fillCorrupted } from '../moore';

type JobTime = {
  jobId: JobId,
  t: number,
  d: number,
  name: string
};

const findMaxTJob = (jobTimes: JobTime[]) =>
  reduce(
    (maxTJob: JobTime, jobTime: JobTime) => maxTJob.t >= jobTime.t ? maxTJob : jobTime,
    { t: -Infinity },
    jobTimes
  );

const updateCTime = (jobTimes: JobTime[]) => {
  let prev = 0;

  const cj = map((jobTime: JobTime) => {
    prev += jobTime.t;

    return { ...jobTime, c: prev };
  }, jobTimes);

  return cj;
};

export const createSchedule = (jobs: JobTime[]) => {
  jobs = fillCorrupted(jobs);

  let fi = reduce((sum, job: JobTime) => sum + job.t, 0, jobs);
  let jobsD = jobs;
  let R = [];

  while (fi > 0) {
    const G = filter((jobTime: JobTime) => jobTime.d >= fi, jobsD);

    if (!G.length) return null;

    const maxTJob = findMaxTJob(G);
    const maxTJobIndex = findIndex(propEq('jobId', maxTJob.jobId), jobsD);

    jobsD = remove(maxTJobIndex, 1, jobsD);
    fi -= maxTJob.t;

    R.push(maxTJob);
  }

  const withC = updateCTime(reverse(R));

  return withC;
};

export default (jobs: JobTime[]) => {
  const schedule = createSchedule(jobs);

  if (!schedule) return null;

  const normalizedSchedule = map((jobTime: JobTime) => ({
    processor: 1,
    startTime: jobTime.c - jobTime.t,
    endTime: jobTime.c,
    delayed: max(0, jobTime.c - jobTime.d),
    name: jobTime.name
  }), schedule);

  return [normalizedSchedule];
};