import Numbers from '../utils/Numbers';

import type { CurrencyMeta, Money } from '../types/api';

/** Formats game money using currency metadata. */
export default class Currency
{
    readonly code: CurrencyMeta['code'];

    readonly symbol: string;

    readonly subunits: number;

    readonly exponent: number;

    readonly subunitsLength: number;

    constructor({ code, symbol, subunits, exponent }: CurrencyMeta)
    {
        this.code = code;
        this.symbol = symbol;
        this.subunits = subunits;
        this.exponent = exponent;
        this.subunitsLength = `${subunits}`.length - 1;
    }

    /**
     * Format a value with the ISO code.
     * @param value
     */
    getFormattedValue(value: Money): string
    {
        return `${this.getFormattedValueNoCurrency(value)} ${this.code}`;
    }

    /**
     * Format a value without the ISO code.
     * @param value
     */
    getFormattedValueNoCurrency(value: Money): string
    {
        const majorUnits = this.toMajorUnits(value);
        const formatted = Numbers.format(majorUnits, this.exponent);

        return this.formatDecimal(formatted);
    }

    private toMajorUnits(value: Money): number
    {
        return value / this.subunits;
    }

    /**
     * Pad decimals and insert thousand separators.
     * @param str
     * @param exponent
     */
    private formatDecimal(str: string, exponent = this.exponent): string
    {
        const regexp = /\B(?=(\d{3})+(?!\d))/g;
        const sanitized = str.replace(/,/g, '');

        if (exponent === 0)
        {
            return sanitized.replace(regexp, ',');
        }

        const [wholePart, decimalPart] = sanitized.split('.');
        const whole = wholePart.replace(regexp, ',');

        if (!decimalPart)
        {
            return `${whole}.00`;
        }

        if (decimalPart.length === 1)
        {
            return `${whole}.${decimalPart}0`;
        }

        return `${whole}.${decimalPart}`;
    }
}
