// creates a graph representation of the input list
function createRelationshipGraph(inputList, idsOnly) {
  const graph = {};

  inputList.forEach(curNode => {
    const { id: curId, parent_id: parentId } = curNode;
    const parentDoesNotExist = typeof graph[parentId] === "undefined";
    const curDoesNotExist = typeof graph[curId] === "undefined";
    const parentIsTopLevel = parentId === null;

    // initialize the parent graph for the first time
    if (parentDoesNotExist) {
      graph[parentId] = {};
    }
    // add the node to the parent graph
    graph[parentId][curId] = idsOnly ? true : curNode;

    // if the current node is a top level node, add itself to the graph
    // if we don't do this, we may miss top level nodes with no children 
    if (parentIsTopLevel && curDoesNotExist) {
      graph[curId] = {};
    }
  });

  return graph;
}

// walks the graph and builds the output list simultaneously
function walkSubGraph(graph, startId) {
  let output = [];
  const isLeafNode = typeof graph[startId] === 'undefined';
  if (isLeafNode) {
    return output;
  }
  Object.keys(graph[startId]).forEach(curId => {
    const curNode = graph[startId][curId];
    output.push(curNode);
    walkSubGraph(graph, curId).forEach(childNode => output.push(childNode));
  });

  return output;
}

module.exports = function sortCategoriesForInsert(inputJson) {
  const inputList = JSON.parse(inputJson);
  const relGraph =  createRelationshipGraph(inputList, false);
  const output = walkSubGraph(relGraph, null);
  return JSON.stringify(output);
}