import { Task } from '../../../types';
import { isPreparedBlockOp } from '../typeGuards';

export const splitTasks = (awaitedTasks: Task[], isFullyExecuted: boolean) => {
  const awaitedTasksBatched: (Task | Task[])[] = [];
  const preparedTasks: (Task | Task[])[] = [];

  awaitedTasks.forEach((task) => {
    if (task.batchId === -1) {
      awaitedTasksBatched.push(task);
      return;
    }

    const latestTask = awaitedTasksBatched.at(-1);

    if (Array.isArray(latestTask) && latestTask.at(-1)?.batchId === task.batchId) {
      latestTask.push(task);
      return;
    }

    awaitedTasksBatched.push([task]);
  });

  awaitedTasksBatched.forEach((task, i) => {
    if (
      i === awaitedTasksBatched.length - 1 ||
      !Array.isArray(task) ||
      (task.length > 1 && task.some(({ op }) => isPreparedBlockOp(op)))
    ) {
      preparedTasks.push(task);
    } else {
      preparedTasks.push(...task.map((task) => ({ ...task, batchId: -1 })));
    }
  });

  let inThreadTasks: Task[] = [];
  let outThreadTasks: Task[] = [];

  if (!isFullyExecuted) {
    const preparedCallTasks = preparedTasks.at(-1)!;
    inThreadTasks = [...(Array.isArray(preparedCallTasks) ? preparedCallTasks : [preparedCallTasks])];
    outThreadTasks = preparedTasks.slice(0, -1).flat();
  } else {
    outThreadTasks = preparedTasks.flat();
  }

  return { inThreadTasks, outThreadTasks };
};
