"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.UNICODE_PLUS_SIGNS = exports.UNICODE_MINUS_SIGNS = exports.SPACE_SEPARATOR_RE = exports.PLUS_SIGNS_WITH_ASCII = exports.PERSIAN_RE = exports.PERSIAN_NUMERALS = exports.PERSIAN_DETECT_RE = exports.PERMILLE_RE = exports.PERMILLE = exports.PERCENT_RE = exports.PERCENTAGES = exports.MINUS_SIGNS_WITH_ASCII = exports.HAN_RE = exports.HAN_NUMERAL_TO_DIGIT = exports.HAN_NUMERALS = exports.HAN_DETECT_RE = exports.FULLWIDTH_RE = exports.FULLWIDTH_NUMERALS = exports.FULLWIDTH_GROUP = exports.FULLWIDTH_DETECT_RE = exports.FULLWIDTH_DECIMAL = exports.BASE_NON_NUMERIC_SYMBOLS = exports.ARABIC_RE = exports.ARABIC_NUMERALS = exports.ARABIC_DETECT_RE = exports.ANY_PLUS_RE = exports.ANY_PLUS_DETECT_RE = exports.ANY_MINUS_RE = exports.ANY_MINUS_DETECT_RE = void 0;
exports.getNumberLocaleDetails = getNumberLocaleDetails;
exports.parseNumber = parseNumber;
var _formatNumber = require("../../utils/formatNumber");
const HAN_NUMERALS = exports.HAN_NUMERALS = ['零', '〇', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
// Map Han numeral characters to ASCII digits. Includes both forms of zero.
const HAN_NUMERAL_TO_DIGIT = exports.HAN_NUMERAL_TO_DIGIT = {
  零: '0',
  〇: '0',
  一: '1',
  二: '2',
  三: '3',
  四: '4',
  五: '5',
  六: '6',
  七: '7',
  八: '8',
  九: '9'
};
const ARABIC_NUMERALS = exports.ARABIC_NUMERALS = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
const PERSIAN_NUMERALS = exports.PERSIAN_NUMERALS = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
const FULLWIDTH_NUMERALS = exports.FULLWIDTH_NUMERALS = ['０', '１', '２', '３', '４', '５', '６', '７', '８', '９'];
const PERCENTAGES = exports.PERCENTAGES = ['%', '٪', '％', '﹪'];
const PERMILLE = exports.PERMILLE = ['‰', '؉'];
const UNICODE_MINUS_SIGNS = exports.UNICODE_MINUS_SIGNS = ['−', '－', '‒', '–', '—', '﹣'];
const UNICODE_PLUS_SIGNS = exports.UNICODE_PLUS_SIGNS = ['＋', '﹢'];

// Fullwidth punctuation common in CJK inputs
const FULLWIDTH_DECIMAL = exports.FULLWIDTH_DECIMAL = '．'; // U+FF0E
const FULLWIDTH_GROUP = exports.FULLWIDTH_GROUP = '，'; // U+FF0C

const ARABIC_RE = exports.ARABIC_RE = new RegExp(`[${ARABIC_NUMERALS.join('')}]`, 'g');
const PERSIAN_RE = exports.PERSIAN_RE = new RegExp(`[${PERSIAN_NUMERALS.join('')}]`, 'g');
const FULLWIDTH_RE = exports.FULLWIDTH_RE = new RegExp(`[${FULLWIDTH_NUMERALS.join('')}]`, 'g');
const HAN_RE = exports.HAN_RE = new RegExp(`[${HAN_NUMERALS.join('')}]`, 'g');
const PERCENT_RE = exports.PERCENT_RE = new RegExp(`[${PERCENTAGES.join('')}]`);
const PERMILLE_RE = exports.PERMILLE_RE = new RegExp(`[${PERMILLE.join('')}]`);

// Detection regexes (non-global to avoid lastIndex side effects)
const ARABIC_DETECT_RE = exports.ARABIC_DETECT_RE = /[٠١٢٣٤٥٦٧٨٩]/;
const PERSIAN_DETECT_RE = exports.PERSIAN_DETECT_RE = /[۰۱۲۳۴۵۶۷۸۹]/;
const HAN_DETECT_RE = exports.HAN_DETECT_RE = /[零〇一二三四五六七八九]/;
const FULLWIDTH_DETECT_RE = exports.FULLWIDTH_DETECT_RE = new RegExp(`[${FULLWIDTH_NUMERALS.join('')}]`);
const BASE_NON_NUMERIC_SYMBOLS = exports.BASE_NON_NUMERIC_SYMBOLS = ['.', ',', FULLWIDTH_DECIMAL, FULLWIDTH_GROUP, '٫', '٬'];
const SPACE_SEPARATOR_RE = exports.SPACE_SEPARATOR_RE = /\p{Zs}/u;
const PLUS_SIGNS_WITH_ASCII = exports.PLUS_SIGNS_WITH_ASCII = ['+', ...UNICODE_PLUS_SIGNS];
const MINUS_SIGNS_WITH_ASCII = exports.MINUS_SIGNS_WITH_ASCII = ['-', ...UNICODE_MINUS_SIGNS];
const escapeRegExp = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const escapeClassChar = s => s.replace(/[-\\\]^]/g, m => `\\${m}`); // escape for use inside [...]

const charClassFrom = chars => `[${chars.map(escapeClassChar).join('')}]`;
const ANY_MINUS_CLASS = charClassFrom(['-'].concat(UNICODE_MINUS_SIGNS));
const ANY_PLUS_CLASS = charClassFrom(['+'].concat(UNICODE_PLUS_SIGNS));
const ANY_MINUS_RE = exports.ANY_MINUS_RE = new RegExp(ANY_MINUS_CLASS, 'gu');
const ANY_PLUS_RE = exports.ANY_PLUS_RE = new RegExp(ANY_PLUS_CLASS, 'gu');
const ANY_MINUS_DETECT_RE = exports.ANY_MINUS_DETECT_RE = new RegExp(ANY_MINUS_CLASS);
const ANY_PLUS_DETECT_RE = exports.ANY_PLUS_DETECT_RE = new RegExp(ANY_PLUS_CLASS);
function getNumberLocaleDetails(locale, options) {
  const parts = (0, _formatNumber.getFormatter)(locale, options).formatToParts(11111.1);
  const result = {};
  parts.forEach(part => {
    result[part.type] = part.value;
  });

  // The formatting options may result in not returning a decimal.
  (0, _formatNumber.getFormatter)(locale).formatToParts(0.1).forEach(part => {
    if (part.type === 'decimal') {
      result[part.type] = part.value;
    }
  });
  return result;
}
function parseNumber(formattedNumber, locale, options) {
  if (formattedNumber == null) {
    return null;
  }

  // Normalize control characters and whitespace; remove bidi/format controls
  let input = String(formattedNumber).replace(/\p{Cf}/gu, '').trim();

  // Normalize unicode minus/plus to ASCII, handle leading/trailing signs
  input = input.replace(ANY_MINUS_RE, '-').replace(ANY_PLUS_RE, '+');
  let isNegative = false;

  // Trailing sign, e.g. "1234-" / "1234+"
  const trailing = input.match(/([+-])\s*$/);
  if (trailing) {
    if (trailing[1] === '-') {
      isNegative = true;
    }
    input = input.replace(/([+-])\s*$/, '');
  }
  // Leading sign
  const leading = input.match(/^\s*([+-])/);
  if (leading) {
    if (leading[1] === '-') {
      isNegative = true;
    }
    input = input.replace(/^\s*[+-]/, '');
  }

  // Heuristic locale detection
  let computedLocale = locale;
  if (computedLocale === undefined) {
    if (ARABIC_DETECT_RE.test(input) || PERSIAN_DETECT_RE.test(input)) {
      computedLocale = 'ar';
    } else if (HAN_DETECT_RE.test(input)) {
      computedLocale = 'zh';
    }
  }
  const {
    group,
    decimal,
    currency
  } = getNumberLocaleDetails(computedLocale, options);

  // Build robust unit regex from all unit parts (such as "km/h")
  const unitParts = (0, _formatNumber.getFormatter)(computedLocale, options).formatToParts(1).filter(p => p.type === 'unit').map(p => escapeRegExp(p.value));
  const unitRegex = unitParts.length ? new RegExp(unitParts.join('|'), 'g') : null;
  let groupRegex = null;
  if (group) {
    const isSpaceGroup = /\p{Zs}/u.test(group);
    const isApostropheGroup = group === "'" || group === '’';

    // Check if the group separator is a space-like character.
    // If so, we'll replace all such characters with an empty string.
    if (isSpaceGroup) {
      groupRegex = /\p{Zs}/gu;
    } else if (isApostropheGroup) {
      // Some environments format numbers with ASCII apostrophe and others with a curly apostrophe.
      groupRegex = /['’]/g;
    } else {
      groupRegex = new RegExp(escapeRegExp(group), 'g');
    }
  }
  const replacements = [{
    regex: group ? groupRegex : null,
    replacement: ''
  }, {
    regex: decimal ? new RegExp(escapeRegExp(decimal), 'g') : null,
    replacement: '.'
  },
  // Fullwidth punctuation
  {
    regex: /．/g,
    replacement: '.'
  },
  // FULLWIDTH_DECIMAL
  {
    regex: /，/g,
    replacement: ''
  },
  // FULLWIDTH_GROUP
  // Arabic punctuation
  {
    regex: /٫/g,
    replacement: '.'
  },
  // ARABIC DECIMAL SEPARATOR (U+066B)
  {
    regex: /٬/g,
    replacement: ''
  },
  // ARABIC THOUSANDS SEPARATOR (U+066C)
  // Currency & unit labels
  {
    regex: currency ? new RegExp(escapeRegExp(currency), 'g') : null,
    replacement: ''
  }, {
    regex: unitRegex,
    replacement: ''
  },
  // Numeral systems to ASCII digits
  {
    regex: ARABIC_RE,
    replacement: ch => String(ARABIC_NUMERALS.indexOf(ch))
  }, {
    regex: PERSIAN_RE,
    replacement: ch => String(PERSIAN_NUMERALS.indexOf(ch))
  }, {
    regex: FULLWIDTH_RE,
    replacement: ch => String(FULLWIDTH_NUMERALS.indexOf(ch))
  }, {
    regex: HAN_RE,
    replacement: ch => HAN_NUMERAL_TO_DIGIT[ch]
  }];
  let unformatted = replacements.reduce((acc, {
    regex,
    replacement
  }) => {
    return regex ? acc.replace(regex, replacement) : acc;
  }, input);

  // Mixed-locale safety: keep only the last '.' as decimal
  const lastDot = unformatted.lastIndexOf('.');
  if (lastDot !== -1) {
    unformatted = `${unformatted.slice(0, lastDot).replace(/\./g, '')}.${unformatted.slice(lastDot + 1).replace(/\./g, '')}`;
  }

  // Guard against Infinity inputs (ASCII and symbol)
  if (/^[-+]?Infinity$/i.test(input) || /[∞]/.test(input)) {
    return null;
  }
  const parseTarget = (isNegative ? '-' : '') + unformatted;
  let num = parseFloat(parseTarget);
  const style = options?.style;
  const isUnitPercent = style === 'unit' && options?.unit === 'percent';
  const hasPercentSymbol = PERCENT_RE.test(formattedNumber) || style === 'percent';
  const hasPermilleSymbol = PERMILLE_RE.test(formattedNumber);
  if (hasPermilleSymbol) {
    num /= 1000;
  } else if (!isUnitPercent && hasPercentSymbol) {
    num /= 100;
  }
  if (Number.isNaN(num)) {
    return null;
  }
  return num;
}