import { get } from 'lodash';

export default function applyFnToKey(doc, key, fn){
  if (key.includes('.$')){
    applyToArrayKey(doc, key, fn);
  } else {
    applyToSingleKey(doc, key, fn);
  }
}

function applyToSingleKey(doc, key, fn){
  // call the function with the current value and document for context
  fn(doc, key);
}

/**
 * Applies the given function to all instances in a document key
 * key.$.with.$.subdocs will apply to all key[i...n].with[j...m].subdocs
 * Warning: Order might be confusing, it will traverse the deepest array in order
 * but the shallower arrays in reverse order
 */
function applyToArrayKey(doc, key, fn){
  const keySplit = key.split('.$');
  // Stack based depth first traversal of arrays
  const array = get(doc, keySplit[0]);
  if (!array) return;
  const stack = [{
    array,
    paths: keySplit.slice(1),
    currentPath: keySplit[0],
    indices: [],
  }];
  while(stack.length){
    const state = stack.pop();
    for (let index in state.array){
      const currentPath = `${state.currentPath}[${index}]${state.paths[0]}`
      if (state.paths.length == 1){
        applyToSingleKey(doc, currentPath, fn);
      } else {
        const array = get(doc, currentPath);
        if (!array) return;
        stack.push({
          array,
          paths: state.paths.slice(1),
          currentPath,
          indices: [...state.indices, index],
        });
      }
    }
  }
}
