import { configFromISO, configFromRFC2822 } from "./from-string.js";
import { configFromArray } from "./from-array.js";
import { getParseRegexForToken } from "../parse/regex.js";
import { addTimeToArrayFromToken } from "../parse/token.js";
import { expandFormat, formatTokenFunctions, formattingTokens } from "../format/format.js";
import checkOverflow from "./check-overflow.js";
import { YEAR, HOUR } from "../units/constants.js";
import { hooks } from "../utils/hooks.js";
import getParsingFlags from "./parsing-flags.js"; // constant that refers to the ISO standard

hooks.ISO_8601 = function () {}; // constant that refers to the RFC 2822 form


hooks.RFC_2822 = function () {}; // date from string and format string


export function configFromStringAndFormat(config) {
  // TODO: Move this to another part of the creation flow to prevent circular deps
  if (config._f === hooks.ISO_8601) {
    configFromISO(config);
    return;
  }

  if (config._f === hooks.RFC_2822) {
    configFromRFC2822(config);
    return;
  }

  config._a = [];
  getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`

  var string = '' + config._i,
      i,
      parsedInput,
      tokens,
      token,
      skipped,
      stringLength = string.length,
      totalParsedInputLength = 0,
      era,
      tokenLen;
  tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
  tokenLen = tokens.length;

  for (i = 0; i < tokenLen; i++) {
    token = tokens[i];
    parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];

    if (parsedInput) {
      skipped = string.substr(0, string.indexOf(parsedInput));

      if (skipped.length > 0) {
        getParsingFlags(config).unusedInput.push(skipped);
      }

      string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
      totalParsedInputLength += parsedInput.length;
    } // don't parse if it's not a known token


    if (formatTokenFunctions[token]) {
      if (parsedInput) {
        getParsingFlags(config).empty = false;
      } else {
        getParsingFlags(config).unusedTokens.push(token);
      }

      addTimeToArrayFromToken(token, parsedInput, config);
    } else if (config._strict && !parsedInput) {
      getParsingFlags(config).unusedTokens.push(token);
    }
  } // add remaining unparsed input length to the string


  getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;

  if (string.length > 0) {
    getParsingFlags(config).unusedInput.push(string);
  } // clear _12h flag if hour is <= 12


  if (config._a[HOUR] <= 12 && getParsingFlags(config).bigHour === true && config._a[HOUR] > 0) {
    getParsingFlags(config).bigHour = undefined;
  }

  getParsingFlags(config).parsedDateParts = config._a.slice(0);
  getParsingFlags(config).meridiem = config._meridiem; // handle meridiem

  config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); // handle era

  era = getParsingFlags(config).era;

  if (era !== null) {
    config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
  }

  configFromArray(config);
  checkOverflow(config);
}

function meridiemFixWrap(locale, hour, meridiem) {
  var isPm;

  if (meridiem == null) {
    // nothing to do
    return hour;
  }

  if (locale.meridiemHour != null) {
    return locale.meridiemHour(hour, meridiem);
  } else if (locale.isPM != null) {
    // Fallback
    isPm = locale.isPM(meridiem);

    if (isPm && hour < 12) {
      hour += 12;
    }

    if (!isPm && hour === 12) {
      hour = 0;
    }

    return hour;
  } else {
    // this is not supposed to happen
    return hour;
  }
}