import isArray from "../utils/is-array";
import isUndefined from "../utils/is-undefined";
import compareArrays from "../utils/compare-arrays";
import { deprecateSimple } from "../utils/deprecate";
import { mergeConfigs } from "./set";
import { Locale } from "./constructor";
import keys from "../utils/keys";

// internal storage for locale config files
var locales = {};
var globalLocale;

function normalizeLocale(key) {
  return key ? key.toLowerCase().replace("_", "-") : key;
}

// pick the locale from the array
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
function chooseLocale(names) {
  var i = 0,
    j,
    next,
    locale,
    split;

  while (i < names.length) {
    split = normalizeLocale(names[i]).split("-");
    j = split.length;
    next = normalizeLocale(names[i + 1]);
    next = next ? next.split("-") : null;
    while (j > 0) {
      locale = loadLocale(split.slice(0, j).join("-"));
      if (locale) {
        return locale;
      }
      if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
        //the next array item is better than a shallower substring of this one
        break;
      }
      j--;
    }
    i++;
  }
  return null;
}

function loadLocale(name) {
  var oldLocale = null;
  // TODO: Find a better way to register and load all the locales in Node
  if (!locales[name] && typeof module !== "undefined" && module && module.exports) {
    try {
      oldLocale = globalLocale._abbr;
      require_once("./locale/" + name);
      // because defineLocale currently also sets the global locale, we
      // want to undo that for lazy loaded locales
      getSetGlobalLocale(oldLocale);
    } catch (e) {}
  }
  return locales[name];
}

// This function will load locale and then set the global locale.  If
// no arguments are passed in, it will simply return the current global
// locale key.
export function getSetGlobalLocale(key, values) {
  var data;
  if (key) {
    if (isUndefined(values)) {
      data = getLocale(key);
    } else {
      data = defineLocale(key, values);
    }

    if (data) {
      // moment.duration._locale = moment._locale = data;
      globalLocale = data;
    }
  }

  return globalLocale._abbr;
}

export function defineLocale(name, config) {
  if (config !== null) {
    config.abbr = name;
    if (locales[name] != null) {
      deprecateSimple("defineLocaleOverride", "use moment.updateLocale(localeName, config) to change " + "an existing locale. moment.defineLocale(localeName, " + "config) should only be used for creating a new locale");
      config = mergeConfigs(locales[name]._config, config);
    } else if (config.parentLocale != null) {
      if (locales[config.parentLocale] != null) {
        config = mergeConfigs(locales[config.parentLocale]._config, config);
      } else {
        // treat as if there is no base config
        deprecateSimple("parentLocaleUndefined", "specified parentLocale is not defined yet");
      }
    }
    locales[name] = new Locale(config);

    // backwards compat for now: also set the locale
    getSetGlobalLocale(name);

    return locales[name];
  } else {
    // useful for testing
    delete locales[name];
    return null;
  }
}

export function updateLocale(name, config) {
  if (config != null) {
    var locale;
    if (locales[name] != null) {
      config = mergeConfigs(locales[name]._config, config);
    }
    locale = new Locale(config);
    locale.parentLocale = locales[name];
    locales[name] = locale;

    // backwards compat for now: also set the locale
    getSetGlobalLocale(name);
  } else {
    // pass null for config to unupdate, useful for tests
    if (locales[name] != null) {
      if (locales[name].parentLocale != null) {
        locales[name] = locales[name].parentLocale;
      } else if (locales[name] != null) {
        delete locales[name];
      }
    }
  }
  return locales[name];
}

// returns locale data
export function getLocale(key) {
  var locale;

  if (key && key._locale && key._locale._abbr) {
    key = key._locale._abbr;
  }

  if (!key) {
    return globalLocale;
  }

  if (!isArray(key)) {
    //short-circuit everything else
    locale = loadLocale(key);
    if (locale) {
      return locale;
    }
    key = [key];
  }

  return chooseLocale(key);
}

export function listLocales() {
  return keys(locales);
}
