type NestedArray<T> = T | NestedArray<T>[];

/**
 * Currency format interface.
 *
 * Each property represents template string used by formatMoney.
 * Inside this template you can use these patterns:
 * - **%s** - Currency symbol
 * - **%v** - Amount
 *
 * **Examples**:
 * ```js
 * '%s %v'   => '$ 1.00'
 * '%s (%v)' => '$ (1.00)'
 * '%s  -- ' => '$  --'
 * ```
 *
 * @typedef {Format} CurrencyFormat
 * @property {String} pos - Currency format for positive values
 * @property {String} [neg=pos] - Currency format for negative values
 * @property {String} [zero=pos] - Currency format for zero values
 *
 */
type CurrencyFormat = {
  pos: string; // Currency format for positive values
  neg?: string; // Currency format for negative values
  zero?: string; // Currency format for zero values
};

/**
 * The library's settings configuration interface.
 *
 * @typedef {Object} Settings
 * @property {String} [symbol='$'] - Currency symbol
 * @property {String|CurrencyFormat} [format='%s%v'] - Controls output: %s = symbol, %v = value (can be object, see docs)
 * @property {String} [decimal='.'] - Decimal point separator
 * @property {String} [thousand=','] - Thousands separator
 * @property {Number} [precision=2] - Number of decimal places to round the amount to
 * @property {Number} [grouping=3] - Digit grouping (not implemented yet)
 * @property {Boolean} [stripZeros=false] - Strip insignificant zeros from decimal part
 * @property {Float} [fallback=0] - Value returned on unformat() failure
 * @property {Number} [round=0] - Decide round direction.
 */
type Settings = {
  symbol?: string; // Currency symbol
  format?: string | CurrencyFormat; // Controls output: %s = symbol, %v = value (can be object, see docs)
  decimal?: string; // Decimal point separator
  thousand?: string; // Thousands separator
  precision?: number; // Number of decimal places to round the amount to
  grouping?: number; // Digit grouping (not implemented yet)
  stripZeros?: boolean; // Strip insignificant zeros from decimal part
  fallback?: number; // Value returned on unformat() failure
  round?: number; // Decide round direction.
};

/**
 * The library's default settings configuration object.
 * Contains default parameters for currency and number formatting.
 *
 * @type {Settings} settings
 */
declare const settings: Settings;

/**
 * Takes a string/array of strings, removes all formatting/cruft and returns the raw float value.
 *
 * Decimal must be included in the regular expression to match floats (defaults to
 * `settings.decimal`), so if the number uses a non-standard decimal
 * separator, provide it as the second argument.
 *
 * Also matches bracketed negatives (eg. `'$ (1.99)' => -1.99`).
 *
 * Doesn't throw any errors (`NaN`s become 0 or provided by fallback value).
 *
 * **Usage:**
 *
 * ```js
 * unformat('£ 12,345,678.90 GBP');
 * // => 12345678.9
 * ```
 *
 * @param {String} value - String containing the number to parse
 * @param {String} [decimal=settings.decimal] - The character used to represent the decimal separator
 * @param {Float} [fallback=settings.fallback] - Value returned on unformat() failure
 * @returns {Float} - Parsed number
 */
declare function unformat(value: string, decimal?: string, fallback?: number): number;
declare function unformatArray(value: NestedArray<string>, decimal?: string, fallback?: number): NestedArray<number>;

/**
 * Implementation of toFixed() that treats floats more like decimals.
 *
 * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present
 * problems for accounting- and finance-related software.
 *
 * **Usage:**
 *
 * ```js
 * // Native toFixed has rounding issues
 * (0.615).toFixed(2);
 * // => '0.61'
 *
 * // With accounting-js
 * toFixed(0.615, 2);
 * // => '0.62'
 * ```
 *
 * @param {Float} value - Float to be treated as a decimal number
 * @param {Number} [precision=settings.precision] - Number of decimal digits to keep
 * @param {Number} [round=settings.round] - Decide round direction
 * @returns {String} - Given number transformed into a string with the given precission
 */
declare function toFixed(value: number, precision?: number, round?: number): string;

/**
 * Format a number, with comma-separated thousands and custom precision/decimal places.
 *
 * **Usage:**
 *
 * ```js
 * // Default usage
 * formatNumber(5318008);
 * // => 5,318,008
 *
 * // Custom format
 * formatNumber(9876543.21, { precision: 3, thousand: " " });
 * // => 9 876 543.210
 * ```
 *
 * @param {Number} number - Number to be formatted
 * @param {Object} [opts={}] - Object containing all the options of the method
 * @returns {String} - Given number properly formatted
  */
declare function formatNumber(number: number, opts?: Settings): string;
declare function formatNumberArray(number: NestedArray<number>, opts?: Settings): NestedArray<string>;

/**
 * Format a number into currency.
 *
 * **Usage:**
 *
 * ```js
 * // Default usage
 * formatMoney(12345678);
 * // => $12,345,678.00
 *
 * // European formatting (custom symbol and separators)
 * formatMoney(4999.99, { symbol: "€", precision: 2, thousand: ".", decimal: "," });
 * // => €4.999,99
 *
 * // Negative values can be formatted nicely
 * formatMoney(-500000, { symbol: "£ ", precision: 0 });
 * // => £ -500,000
 *
 * // Simple `format` string allows control of symbol position (%v = value, %s = symbol)
 * formatMoney(5318008, { symbol: "GBP",  format: "%v %s" });
 * // => 5,318,008.00 GBP
 * ```
 *
 * @param {Number} amount - Amount to be formatted
 * @param {Object} [opts={}] - Object containing all the options of the method
 * @returns {String} - Given number properly formatted as money
 */
declare function formatMoney(amount: number, opts?: Settings): string;
declare function formatMoneyArray(amount: NestedArray<number>, opts?: Settings): NestedArray<string>;

export { type CurrencyFormat, type Settings, formatMoney, formatMoneyArray, formatNumber, formatNumberArray, settings, toFixed, unformat, unformatArray };
