/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { defaultLocale } from "@arcgis/toolkit/intl";
import { n as numberKeys } from "./key.js";
const unnecessaryDecimal = new RegExp(`\\${"."}(0+)?$`);
const trailingZeros = new RegExp("0+$");
class BigDecimal {
  static {
    this.DECIMALS = 100;
  }
  static {
    this.ROUNDED = true;
  }
  static {
    this.SHIFT = BigInt("1" + "0".repeat(this.DECIMALS));
  }
  // derived constant
  constructor(input) {
    if (input instanceof BigDecimal) {
      return input;
    }
    const [integers, decimals] = expandExponentialNumberString(input).split(".").concat("");
    this.value = BigInt(integers + decimals.padEnd(BigDecimal.DECIMALS, "0").slice(0, BigDecimal.DECIMALS)) + BigInt(BigDecimal.ROUNDED && decimals[BigDecimal.DECIMALS] >= "5");
    this.isNegative = input.charAt(0) === "-";
  }
  static {
    this._divRound = (dividend, divisor) => BigDecimal.fromBigInt(
      dividend / divisor + (BigDecimal.ROUNDED ? dividend * BigInt(2) / divisor % BigInt(2) : BigInt(0))
    );
  }
  static {
    this.fromBigInt = (bigint) => Object.assign(Object.create(BigDecimal.prototype), { value: bigint, isNegative: bigint < BigInt(0) });
  }
  getIntegersAndDecimals() {
    const s = this.value.toString().replace("-", "").padStart(BigDecimal.DECIMALS + 1, "0");
    const integers = s.slice(0, -BigDecimal.DECIMALS);
    const decimals = s.slice(-BigDecimal.DECIMALS).replace(trailingZeros, "");
    return { integers, decimals };
  }
  toString() {
    const { integers, decimals } = this.getIntegersAndDecimals();
    return `${this.isNegative ? "-" : ""}${integers}${decimals.length ? "." + decimals : ""}`;
  }
  formatToParts(formatter) {
    const { integers, decimals } = this.getIntegersAndDecimals();
    const parts = formatter.numberFormatter.formatToParts(BigInt(integers));
    if (this.isNegative) {
      parts.unshift({ type: "minusSign", value: formatter.minusSign });
    }
    if (decimals.length) {
      parts.push({ type: "decimal", value: formatter.decimal });
      decimals.split("").forEach((char) => parts.push({ type: "fraction", value: char }));
    }
    return parts;
  }
  format(formatter) {
    const { integers, decimals } = this.getIntegersAndDecimals();
    const integersFormatted = `${this.isNegative ? formatter.minusSign : ""}${formatter.numberFormatter.format(
      BigInt(integers)
    )}`;
    const decimalsFormatted = decimals.length ? `${formatter.decimal}${decimals.split("").map((char) => formatter.numberFormatter.format(Number(char))).join("")}` : "";
    return `${integersFormatted}${decimalsFormatted}`;
  }
  add(n) {
    return BigDecimal.fromBigInt(this.value + new BigDecimal(n).value);
  }
  subtract(n) {
    return BigDecimal.fromBigInt(this.value - new BigDecimal(n).value);
  }
  multiply(n) {
    return BigDecimal._divRound(this.value * new BigDecimal(n).value, BigDecimal.SHIFT);
  }
  divide(n) {
    return BigDecimal._divRound(this.value * BigDecimal.SHIFT, new BigDecimal(n).value);
  }
}
function isValidNumber(numberString) {
  return !(!numberString || isNaN(Number(numberString)));
}
function parseNumberString(numberString) {
  if (!numberString || !stringContainsNumbers(numberString)) {
    return "";
  }
  return sanitizeExponentialNumberString(numberString, (nonExpoNumString) => {
    let containsDecimal = false;
    const result = nonExpoNumString.split("").filter((value, i) => {
      if (value.match(/\./g) && !containsDecimal) {
        containsDecimal = true;
        return true;
      }
      if (value.match(/-/g) && i === 0) {
        return true;
      }
      return numberKeys.includes(value);
    }).join("");
    return isValidNumber(result) ? new BigDecimal(result).toString() : "";
  });
}
const allLeadingZerosOptionallyNegative = /^([-0])0+(?=\d)/;
const decimalOnlyAtEndOfString = /(?!^\.)\.$/;
const allHyphensExceptTheStart = /(?!^-)-/g;
const isNegativeDecimalOnlyZeros = /^-\b0\b\.?0*$/;
const hasTrailingDecimalZeros = /0*$/;
const charAllowlist = /* @__PURE__ */ new Set(["e", "E", "-", ",", ".", ...numberKeys]);
const sanitizeNumberString = (numberString) => {
  const strippedInvalidCharsValue = Array.from(numberString).filter((char) => charAllowlist.has(char)).join("");
  return sanitizeExponentialNumberString(strippedInvalidCharsValue, (nonExpoNumString) => {
    const sanitizedValue = nonExpoNumString.replace(allHyphensExceptTheStart, "").replace(decimalOnlyAtEndOfString, "").replace(allLeadingZerosOptionallyNegative, "$1");
    return isValidNumber(sanitizedValue) ? isNegativeDecimalOnlyZeros.test(sanitizedValue) ? sanitizedValue : getBigDecimalAsString(sanitizedValue) : nonExpoNumString;
  });
};
function getBigDecimalAsString(sanitizedValue) {
  const sanitizedValueDecimals = sanitizedValue.split(".")[1];
  const value = new BigDecimal(sanitizedValue).toString();
  const [bigDecimalValueInteger, bigDecimalValueDecimals] = value.split(".");
  return sanitizedValueDecimals && bigDecimalValueDecimals !== sanitizedValueDecimals ? `${bigDecimalValueInteger}.${sanitizedValueDecimals}` : value;
}
function sanitizeExponentialNumberString(numberString, func) {
  if (!numberString) {
    return numberString;
  }
  const firstE = numberString.toLowerCase().indexOf("e") + 1;
  if (!firstE) {
    return func(numberString);
  }
  return numberString.replace(/[eE]*$/g, "").substring(0, firstE).concat(numberString.slice(firstE).replace(/[eE]/g, "")).split(/[eE]/).map((section, i) => i === 1 ? func(section.replace(/\./g, "")) : func(section)).join("e").replace(/^e/, "1e");
}
function expandExponentialNumberString(numberString) {
  const exponentialParts = numberString.split(/[eE]/);
  if (exponentialParts.length === 1) {
    return numberString;
  }
  const number = +numberString;
  if (Number.isSafeInteger(number)) {
    return `${number}`;
  }
  const isNegative = numberString.charAt(0) === "-";
  const magnitude = +exponentialParts[1];
  const decimalParts = exponentialParts[0].split(".");
  const integers = (isNegative ? decimalParts[0].substring(1) : decimalParts[0]) || "";
  const decimals = decimalParts[1] || "";
  const shiftDecimalLeft = (integers2, magnitude2) => {
    const magnitudeDelta = Math.abs(magnitude2) - integers2.length;
    const leftPaddedZeros = magnitudeDelta > 0 ? `${"0".repeat(magnitudeDelta)}${integers2}` : integers2;
    const shiftedDecimal = `${leftPaddedZeros.slice(0, magnitude2)}${"."}${leftPaddedZeros.slice(magnitude2)}`;
    return shiftedDecimal;
  };
  const shiftDecimalRight = (decimals2, magnitude2) => {
    const rightPaddedZeros = magnitude2 > decimals2.length ? `${decimals2}${"0".repeat(magnitude2 - decimals2.length)}` : decimals2;
    const shiftedDecimal = `${rightPaddedZeros.slice(0, magnitude2)}${"."}${rightPaddedZeros.slice(magnitude2)}`;
    return shiftedDecimal;
  };
  const expandedNumberString = magnitude > 0 ? `${integers}${shiftDecimalRight(decimals, magnitude)}` : `${shiftDecimalLeft(integers, magnitude)}${decimals}`;
  return `${isNegative ? "-" : ""}${expandedNumberString.charAt(0) === "." ? "0" : ""}${expandedNumberString.replace(unnecessaryDecimal, "").replace(allLeadingZerosOptionallyNegative, "")}`;
}
function stringContainsNumbers(string) {
  return numberKeys.some((number) => string.includes(number));
}
function addLocalizedTrailingDecimalZeros(localizedValue, value, formatter) {
  const decimals = value.split(".")[1];
  if (decimals) {
    const trailingDecimalZeros = decimals.match(hasTrailingDecimalZeros)?.[0];
    if (trailingDecimalZeros && formatter.delocalize(localizedValue).length !== value.length && decimals.indexOf("e") === -1) {
      const decimalSeparator = formatter.decimal;
      localizedValue = !localizedValue.includes(decimalSeparator) ? `${localizedValue}${decimalSeparator}` : localizedValue;
      return localizedValue.padEnd(localizedValue.length + trailingDecimalZeros.length, formatter.localize("0"));
    }
  }
  return localizedValue;
}
const localizedTwentyFourHourMeridiems = new Map(
  Object.entries({
    bg: { am: "пр.об.", pm: "сл.об." },
    bs: { am: "prijepodne", pm: "popodne" },
    ca: { am: "a. m.", pm: "p. m." },
    cs: { am: "dop.", pm: "odp." },
    es: { am: "a. m.", pm: "p. m." },
    "es-mx": { am: "a.m.", pm: "p.m." },
    "es-MX": { am: "a.m.", pm: "p.m." },
    fi: { am: "ap.", pm: "ip." },
    he: { am: "לפנה״צ", pm: "אחה״צ" },
    hu: { am: "de. ", pm: "du." },
    lt: { am: "priešpiet", pm: "popiet" },
    lv: { am: "priekšpusdienā", pm: "pēcpusdienā" },
    mk: { am: "претпл.", pm: "попл." },
    no: { am: "a.m.", pm: "p.m." },
    nl: { am: "a.m.", pm: "p.m." },
    "pt-pt": { am: "da manhã", pm: "da tarde" },
    "pt-PT": { am: "da manhã", pm: "da tarde" },
    ro: { am: "a.m.", pm: "p.m." },
    sl: { am: "dop.", pm: "pop." },
    sv: { am: "fm", pm: "em" },
    th: { am: "ก่อนเที่ยง", pm: "หลังเที่ยง" },
    tr: { am: "ÖÖ", pm: "ÖS" },
    uk: { am: "дп", pm: "пп" },
    vi: { am: "SA", pm: "CH" }
  })
);
const numberingSystems = ["arab", "arabext", "latn"];
const isNumberingSystemSupported = (numberingSystem) => !!(numberingSystems && numberingSystems.includes(numberingSystem));
const browserNumberingSystem = new Intl.NumberFormat().resolvedOptions().numberingSystem;
const defaultNumberingSystem = browserNumberingSystem === "arab" || !isNumberingSystemSupported(browserNumberingSystem) ? "latn" : browserNumberingSystem;
const getSupportedNumberingSystem = (numberingSystem) => isNumberingSystemSupported(numberingSystem) ? numberingSystem : defaultNumberingSystem;
function getDateFormatSupportedLocale(locale) {
  switch (locale) {
    case "it-CH":
      return "de-CH";
    case "bs":
      return "sr-Latn-CS";
    default:
      return locale;
  }
}
class NumberStringFormat {
  constructor() {
    this.delocalize = (numberString) => {
      if (!this._numberFormatOptions) {
        return numberString;
      }
      return sanitizeExponentialNumberString(
        numberString,
        (nonExponentialNumberString) => this.#normalizeDigitsAndSign(this.#normalizeSeparators(nonExponentialNumberString))
      );
    };
    this.localize = (numberString) => {
      return this._numberFormatOptions ? sanitizeExponentialNumberString(
        numberString,
        (nonExpoNumString) => isValidNumber(nonExpoNumString.trim()) ? new BigDecimal(nonExpoNumString.trim()).format(this).replace(new RegExp(`[${this._actualGroup}]`, "g"), this._group) : nonExpoNumString
      ) : numberString;
    };
  }
  get group() {
    return this._group;
  }
  get decimal() {
    return this._decimal;
  }
  get minusSign() {
    return this._minusSign;
  }
  get digits() {
    return this._digits;
  }
  get numberFormatter() {
    return this._numberFormatter;
  }
  get numberFormatOptions() {
    return this._numberFormatOptions;
  }
  /** numberFormatOptions needs to be set before localize/delocalize is called to ensure the options are up to date */
  set numberFormatOptions(options) {
    options.numberingSystem = getSupportedNumberingSystem(options?.numberingSystem);
    options.locale = options?.locale || defaultLocale;
    if (
      // No need to create the formatter if `locale` and `numberingSystem`
      // are the default values and `numberFormatOptions` has not been set
      !this._numberFormatOptions && options.locale === defaultLocale && options.numberingSystem === defaultNumberingSystem && // don't skip initialization if any options besides locale/numberingSystem are set
      Object.keys(options).length === 2 || // cache formatter by only recreating when options change
      JSON.stringify(this._numberFormatOptions) === JSON.stringify(options)
    ) {
      return;
    }
    this._numberFormatOptions = options;
    this._numberFormatter = new Intl.NumberFormat(this._numberFormatOptions.locale, this._numberFormatOptions);
    this._digits = [
      ...new Intl.NumberFormat(this._numberFormatOptions.locale, {
        useGrouping: false,
        numberingSystem: this._numberFormatOptions.numberingSystem
      }).format(9876543210)
    ].reverse();
    const index = new Map(this._digits.map((d, i) => [d, i]));
    const parts = new Intl.NumberFormat(this._numberFormatOptions.locale, {
      numberingSystem: this._numberFormatOptions.numberingSystem
    }).formatToParts(-123456789e-1);
    this._actualGroup = parts.find((d) => d.type === "group").value;
    this._group = this._actualGroup.trim().length === 0 || this._actualGroup == " " ? " " : this._actualGroup;
    this._decimal = options.locale === "bs" || options.locale === "mk" ? "," : parts.find((d) => d.type === "decimal").value;
    this._minusSign = parts.find((d) => d.type === "minusSign").value;
    this._getDigitIndex = (d) => index.get(d);
  }
  #normalizeDigitsAndSign(value) {
    return value.replace(new RegExp(`[${this._minusSign}]`, "g"), "-").replace(new RegExp(`[${this._digits.join("")}]`, "g"), this._getDigitIndex);
  }
  #normalizeSeparators(value) {
    if (this._group !== this._decimal) {
      return value.replace(new RegExp(`[${this._group}]`, "g"), "").replace(new RegExp(`[${this._decimal}]`, "g"), ".");
    }
    const lastSeparatorIndex = value.lastIndexOf(this._decimal);
    if (lastSeparatorIndex === -1) {
      return value;
    }
    const wholePart = value.slice(0, lastSeparatorIndex).replace(new RegExp(`[${this._group}]`, "g"), "");
    const fractionalPart = value.slice(lastSeparatorIndex + 1);
    return `${wholePart}.${fractionalPart}`;
  }
}
const numberStringFormatter = new NumberStringFormat();
let dateTimeFormatCache;
let previousLocaleUsedForCaching;
function buildDateTimeFormatCacheKey(options = {}) {
  return Object.entries(options).sort(([key1], [key2]) => key1.localeCompare(key2)).map((keyValue) => `${keyValue[0]}-${keyValue[1]}`).flat().join(":");
}
function getDateTimeFormat(locale, options) {
  if (!dateTimeFormatCache) {
    dateTimeFormatCache = /* @__PURE__ */ new Map();
  }
  if (previousLocaleUsedForCaching !== locale) {
    dateTimeFormatCache.clear();
    previousLocaleUsedForCaching = locale;
  }
  const key = buildDateTimeFormatCacheKey(options);
  const cached = dateTimeFormatCache.get(key);
  if (cached) {
    return cached;
  }
  const format = new Intl.DateTimeFormat(locale, options);
  dateTimeFormatCache.set(key, format);
  return format;
}
export {
  BigDecimal as B,
  NumberStringFormat as N,
  addLocalizedTrailingDecimalZeros as a,
  getSupportedNumberingSystem as b,
  getDateFormatSupportedLocale as c,
  getDateTimeFormat as g,
  isValidNumber as i,
  localizedTwentyFourHourMeridiems as l,
  numberStringFormatter as n,
  parseNumberString as p,
  sanitizeNumberString as s
};
