import { addFormatToken } from "../format/format.js";
import { addRegexToken, matchUnsigned, regexEscape } from "../parse/regex.js";
import { addParseToken } from "../parse/token.js";
import { YEAR } from "./constants.js";
import { hooks as moment } from "../utils/hooks.js";
import { getLocale } from "../locale/locales.js";
import getParsingFlags from "../create/parsing-flags.js";
import hasOwnProp from "../utils/has-own-prop.js";
addFormatToken('N', 0, 0, 'eraAbbr');
addFormatToken('NN', 0, 0, 'eraAbbr');
addFormatToken('NNN', 0, 0, 'eraAbbr');
addFormatToken('NNNN', 0, 0, 'eraName');
addFormatToken('NNNNN', 0, 0, 'eraNarrow');
addFormatToken('y', ['y', 1], 'yo', 'eraYear');
addFormatToken('y', ['yy', 2], 0, 'eraYear');
addFormatToken('y', ['yyy', 3], 0, 'eraYear');
addFormatToken('y', ['yyyy', 4], 0, 'eraYear');
addRegexToken('N', matchEraAbbr);
addRegexToken('NN', matchEraAbbr);
addRegexToken('NNN', matchEraAbbr);
addRegexToken('NNNN', matchEraName);
addRegexToken('NNNNN', matchEraNarrow);
addParseToken(['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], function (input, array, config, token) {
  var era = config._locale.erasParse(input, token, config._strict);

  if (era) {
    getParsingFlags(config).era = era;
  } else {
    getParsingFlags(config).invalidEra = input;
  }
});
addRegexToken('y', matchUnsigned);
addRegexToken('yy', matchUnsigned);
addRegexToken('yyy', matchUnsigned);
addRegexToken('yyyy', matchUnsigned);
addRegexToken('yo', matchEraYearOrdinal);
addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
addParseToken(['yo'], function (input, array, config, token) {
  var match;

  if (config._locale._eraYearOrdinalRegex) {
    match = input.match(config._locale._eraYearOrdinalRegex);
  }

  if (config._locale.eraYearOrdinalParse) {
    array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
  } else {
    array[YEAR] = parseInt(input, 10);
  }
});
export function localeEras(m, format) {
  var i,
      l,
      date,
      eras = this._eras || getLocale('en')._eras;

  for (i = 0, l = eras.length; i < l; ++i) {
    switch (typeof eras[i].since) {
      case 'string':
        // truncate time
        date = moment(eras[i].since).startOf('day');
        eras[i].since = date.valueOf();
        break;
    }

    switch (typeof eras[i].until) {
      case 'undefined':
        eras[i].until = +Infinity;
        break;

      case 'string':
        // truncate time
        date = moment(eras[i].until).startOf('day').valueOf();
        eras[i].until = date.valueOf();
        break;
    }
  }

  return eras;
}
export function localeErasParse(eraName, format, strict) {
  var i,
      l,
      eras = this.eras(),
      name,
      abbr,
      narrow;
  eraName = eraName.toUpperCase();

  for (i = 0, l = eras.length; i < l; ++i) {
    name = eras[i].name.toUpperCase();
    abbr = eras[i].abbr.toUpperCase();
    narrow = eras[i].narrow.toUpperCase();

    if (strict) {
      switch (format) {
        case 'N':
        case 'NN':
        case 'NNN':
          if (abbr === eraName) {
            return eras[i];
          }

          break;

        case 'NNNN':
          if (name === eraName) {
            return eras[i];
          }

          break;

        case 'NNNNN':
          if (narrow === eraName) {
            return eras[i];
          }

          break;
      }
    } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
      return eras[i];
    }
  }
}
export function localeErasConvertYear(era, year) {
  var dir = era.since <= era.until ? +1 : -1;

  if (year === undefined) {
    return moment(era.since).year();
  } else {
    return moment(era.since).year() + (year - era.offset) * dir;
  }
}
export function getEraName() {
  var i,
      l,
      val,
      eras = this.localeData().eras();

  for (i = 0, l = eras.length; i < l; ++i) {
    // truncate time
    val = this.clone().startOf('day').valueOf();

    if (eras[i].since <= val && val <= eras[i].until) {
      return eras[i].name;
    }

    if (eras[i].until <= val && val <= eras[i].since) {
      return eras[i].name;
    }
  }

  return '';
}
export function getEraNarrow() {
  var i,
      l,
      val,
      eras = this.localeData().eras();

  for (i = 0, l = eras.length; i < l; ++i) {
    // truncate time
    val = this.clone().startOf('day').valueOf();

    if (eras[i].since <= val && val <= eras[i].until) {
      return eras[i].narrow;
    }

    if (eras[i].until <= val && val <= eras[i].since) {
      return eras[i].narrow;
    }
  }

  return '';
}
export function getEraAbbr() {
  var i,
      l,
      val,
      eras = this.localeData().eras();

  for (i = 0, l = eras.length; i < l; ++i) {
    // truncate time
    val = this.clone().startOf('day').valueOf();

    if (eras[i].since <= val && val <= eras[i].until) {
      return eras[i].abbr;
    }

    if (eras[i].until <= val && val <= eras[i].since) {
      return eras[i].abbr;
    }
  }

  return '';
}
export function getEraYear() {
  var i,
      l,
      dir,
      val,
      eras = this.localeData().eras();

  for (i = 0, l = eras.length; i < l; ++i) {
    dir = eras[i].since <= eras[i].until ? +1 : -1; // truncate time

    val = this.clone().startOf('day').valueOf();

    if (eras[i].since <= val && val <= eras[i].until || eras[i].until <= val && val <= eras[i].since) {
      return (this.year() - moment(eras[i].since).year()) * dir + eras[i].offset;
    }
  }

  return this.year();
}
export function erasNameRegex(isStrict) {
  if (!hasOwnProp(this, '_erasNameRegex')) {
    computeErasParse.call(this);
  }

  return isStrict ? this._erasNameRegex : this._erasRegex;
}
export function erasAbbrRegex(isStrict) {
  if (!hasOwnProp(this, '_erasAbbrRegex')) {
    computeErasParse.call(this);
  }

  return isStrict ? this._erasAbbrRegex : this._erasRegex;
}
export function erasNarrowRegex(isStrict) {
  if (!hasOwnProp(this, '_erasNarrowRegex')) {
    computeErasParse.call(this);
  }

  return isStrict ? this._erasNarrowRegex : this._erasRegex;
}

function matchEraAbbr(isStrict, locale) {
  return locale.erasAbbrRegex(isStrict);
}

function matchEraName(isStrict, locale) {
  return locale.erasNameRegex(isStrict);
}

function matchEraNarrow(isStrict, locale) {
  return locale.erasNarrowRegex(isStrict);
}

function matchEraYearOrdinal(isStrict, locale) {
  return locale._eraYearOrdinalRegex || matchUnsigned;
}

function computeErasParse() {
  var abbrPieces = [],
      namePieces = [],
      narrowPieces = [],
      mixedPieces = [],
      i,
      l,
      eras = this.eras();

  for (i = 0, l = eras.length; i < l; ++i) {
    namePieces.push(regexEscape(eras[i].name));
    abbrPieces.push(regexEscape(eras[i].abbr));
    narrowPieces.push(regexEscape(eras[i].narrow));
    mixedPieces.push(regexEscape(eras[i].name));
    mixedPieces.push(regexEscape(eras[i].abbr));
    mixedPieces.push(regexEscape(eras[i].narrow));
  }

  this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
  this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
  this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
  this._erasNarrowRegex = new RegExp('^(' + narrowPieces.join('|') + ')', 'i');
}