var _ = require('lodash');
var endings = require('./lib/endings');
var lettersToTonify = require('./lib/letters-to-tonify');
var toneMap = require('./lib/tone-map');
var toneNumbers = [1, 2, 3, 4];

module.exports = tonifyPhrase;

/**
 * @param {string} phrase
 * @return {string}
 */
function tonifyPhrase(phrase) {
  var words = splitPhraseIntoWords(phrase);
  var tonifiedWords = words.map(tonifyWord);

  return tonifiedWords.join(' ');
}

/**
 * @param {string} word
 * @return {string}
 */
function tonifyWord(word) {
  var tone = getTone(word);
  var ending = getEnding(word);

  if (!tone || !ending) {
    return getTonelessFallback(word);
  }

  // TODO: Refactor this exception.
  if (_.includes(['nue', 'lue'], stripToneNumber(word))) {
    word = word.replace('u', 'ü');
    ending = ending.replace('u', 'ü');
  }

  var tonifiedEnding = tonifyEnding(ending, tone);
  var tonifiedWord = word.replace(ending, tonifiedEnding);

  return stripToneNumber(tonifiedWord);
}

/**
 * @param {string} word
 * @return {string}
 */
function getTonelessFallback(word) {
  switch (word) {
    case 'lv':
      return 'lü';

    case 'nv':
      return 'nü';

    case 'lue':
      return 'lüe';

    case 'nue':
      return 'nüe';

    default:
      return word;
  }
}

/**
 * @param {string} letter
 * @param {number} tone
 * @return {string}
 */
function tonifyLetter(letter, tone) {
  var keys = letter + '.' + tone;
  return _.get(toneMap, keys, letter);
}

/**
 * @param {string} ending
 * @param {number} tone
 * @return {string}
 */
function tonifyEnding(ending, tone) {
  var letter;

  _.forEach(lettersToTonify, function(letterAndPattern) {
    if (!letter && ending.match(letterAndPattern.pattern)) {
      letter = letterAndPattern.letter;
    }
  });

  if (!letter) {
    return ending;
  }

  return ending.replace(letter, tonifyLetter(letter, tone));
}

/**
 * @param {string} word
 * @return {string}
 */
function stripToneNumber(word) {
  return _.trim(word, toneNumbers);
}

/**
 * @param {string} phrase
 * @return {array}
 */
function splitPhraseIntoWords(phrase) {
  return phrase.split(' ');
}

/**
 * @param {string} word
 * @return {number|null}
 */
function getTone(word) {
  var lastCharacter = parseInt(_.last(word), 10);
  return _.includes(toneNumbers, lastCharacter) ? lastCharacter : null;
}

/**
 * @param {string} word
 * @return {string|null}
 */
function getEnding(word) {
  var ending = null;

  _.forEach(endings, function(pattern, plainEnding) {
    if (word.match(pattern)) {
      ending = plainEnding;
    }
  });

  return ending;
}

@@ -1070,151 +1070,95 @@
 %7B%0A  
-switch (word) %7B%0A    case 'lv':%0A      return
+var fallbackIoMap = %7B%0A    lv:
  'l%C3%BC'
-;%0A
+,
 %0A    
-case 'nv':%0A      return
+nv:
  'n%C3%BC'
-;%0A
+,
 %0A    
-case 'lue':%0A      return
+lue:
  'l%C3%BCe'
-;%0A
+,
 %0A    
-case 'nu
+nue: 'n%C3%BC
 e'
-:
 %0A  
-  
+%7D;%0A%0A
   re
@@ -1166,51 +1166,41 @@
 urn 
-'n%C3%BCe';%0A%0A    default:%0A      return word;%0A  %7D
+_.get(fallbackIoMap, word, word);
 %0A%7D%0A%0A

Refactor and simplify switch statement