import * as i0 from '@angular/core';
import { inject, Injectable, Pipe, NgModule } from '@angular/core';
import { currencies } from '@seniorsistemas/angular-components/currency';
import { LocaleService } from '@seniorsistemas/angular-components/locale';
import { isNullOrUndefined } from '@seniorsistemas/angular-components/utils';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

/**
 * @description Service for formatting numeric values using the browser's `Intl.NumberFormat` API.
 * Automatically uses the locale configured in `LocaleService` unless explicitly overridden.
 * Supports `BigNumber`, plain numbers, and numeric strings, as well as currency display styles.
 *
 * @example
 * ```typescript
 * // Inject the service
 * const numericService = inject(NumericService);
 *
 * // Format a number with the active locale
 * const formatted = numericService.instant(1234567.89);
 *
 * // Format as currency
 * const currency = numericService.instant(1234.5, {
 *   numberFormatOptions: { style: 'currency', currency: 'BRL' }
 * });
 * ```
 * @category Numeric
 */
class NumericService {
    localeService = inject(LocaleService);
    /**
     * Wrapper around Intl.NumberFormat that returns the localized value using the user's locale by default(platform's preferential language).
     * This method should only be used after the localeService has been initialized by the host application, either by a resolver or a manual call.
     * Can be overwritten by the provided Intl.NumberFormatOptions.
     * Documentation is available at {@link https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat Intl.NumberFormatOptions}.
     * @param {number | string | BigNumber} value The value to be formatted.
     * @param options Locale and numberFormatOptions that overwrites the default Intl.NumberFormatOptions.
     * @return `string` The formatted value.
     */
    instant(value, options) {
        if (isNullOrUndefined(value))
            return null;
        options = {
            ...options,
            locale: options?.locale ?? this.localeService.getLocaleOptions()?.locale ?? 'pt-BR',
            numberFormatOptions: {
                useGrouping: true,
                ...options?.numberFormatOptions,
                currency: options?.numberFormatOptions?.style === 'currency'
                    ? (options?.numberFormatOptions?.currency ?? 'BRL')
                    : undefined,
                currencyDisplay: options?.numberFormatOptions?.style === 'currency'
                    ? (options?.numberFormatOptions?.currencyDisplay ?? 'narrowSymbol')
                    : undefined,
                minimumFractionDigits: (options?.numberFormatOptions?.minimumFractionDigits ?? options?.numberFormatOptions?.currency)
                    ? (this.getCurrencyMinimumFractionDigits(options?.numberFormatOptions?.currency) ??
                        undefined)
                    : undefined,
                roundingMode: 'trunc',
            },
        };
        // From https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
        return new Intl.NumberFormat(options.locale, options.numberFormatOptions).format(this.getType(value) === 'number' || this.getType(value) === 'string'
            ? value
            : value.toString());
    }
    getCurrencyMinimumFractionDigits(currency) {
        if (!currency)
            return null;
        return currencies[currency]?.scale;
    }
    getType(value) {
        // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
        if (value === null)
            return 'null';
        if (value === undefined)
            return 'undefined';
        const baseType = typeof value;
        // Primitive types
        if (baseType !== 'object' && baseType !== 'function') {
            return baseType;
        }
        // Symbol.toStringTag often specifies the "display name" of the
        // object's class. It's used in Object.prototype.toString().
        const tag = value[Symbol.toStringTag];
        if (typeof tag === 'string') {
            return tag;
        }
        // If it's a function whose source code starts with the "class" keyword
        if (baseType === 'function' && Function.prototype.toString.call(value).startsWith('class')) {
            return 'class';
        }
        // The name of the constructor; for example `Array`, `GeneratorFunction`,
        // `Number`, `String`, `Boolean` or `MyCustomClass`
        const className = value.constructor.name;
        if (typeof className === 'string' && className !== '') {
            return className;
        }
        // At this point there's no robust way to get the type of value,
        // so we use the base implementation.
        return baseType;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });

/**
 * @description Angular pipe for formatting numeric values according to the active locale.
 * Wraps `NumericService.instant()` and reactively responds to locale changes via `LocaleService`.
 * Accepts an optional `locale` override and `Intl.NumberFormatOptions` for fine-grained control.
 *
 * @example
 * ```html
 * <!-- Basic usage -->
 * {{ 1234.56 | numeric | async }}
 *
 * <!-- With locale override and fraction digits -->
 * {{ 1234.56 | numeric:{ locale: 'en-US', numberFormatOptions: { minimumFractionDigits: 2 } } | async }}
 * ```
 * @category Numeric
 */
class NumericPipe {
    numericService = inject(NumericService);
    localeService = inject(LocaleService);
    transform(value, options) {
        return options?.locale
            ? of(this.numericService.instant(value, options))
            : this.localeService.getLocale().pipe(map((locale) => this.numericService.instant(value, {
                locale,
                numberFormatOptions: options?.numberFormatOptions,
            })));
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
    static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: NumericPipe, isStandalone: true, name: "numeric" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'numeric',
                    standalone: true,
                }]
        }] });

class NumericModule {
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
    static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: NumericModule, imports: [NumericPipe], exports: [NumericPipe] });
    static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericModule });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NumericModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [NumericPipe],
                    exports: [NumericPipe],
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { NumericModule, NumericPipe, NumericService };
//# sourceMappingURL=seniorsistemas-angular-components-numeric.mjs.map
