// TODO inspect why the following is erroring on angular build
import { format as dateFnsFormat } from 'date-fns';
import { sentenceCase } from 'sentence-case';
import { DEFAULT_DATE_FORMAT_PATTERN } from '../Constants/GeneralConstants';
import Helper from './Helper';
import StringExtensions from '../Extensions/StringExtensions';
export function NumberFormatter(input, options = {}, rowNode, column, api) {
    let preparedInput;
    if (options.Content) {
        const context = {
            column,
            rowNode,
            input,
            api,
        };
        preparedInput = formatPlaceholder(options.Content.toString(), context);
    }
    else {
        preparedInput = input;
    }
    if (preparedInput == null || preparedInput == undefined) {
        return undefined;
    }
    if (typeof preparedInput === 'string') {
        return preparedInput;
    }
    let n = Number(preparedInput);
    if (isNaN(n)) {
        return preparedInput.toString();
    }
    const fractionsSepatator = options.FractionSeparator ? options.FractionSeparator : '.';
    let multiplier = options.Multiplier ? options.Multiplier : 1;
    if (options.Multiplier !== undefined) {
        n *= multiplier;
        n = parseFloat(n.toFixed(12));
    }
    // Set Integer and Fraction Digits to a max of 20
    if (options.IntegerDigits > 20) {
        options.IntegerDigits = 20;
    }
    if (options.FractionDigits > 20) {
        options.FractionDigits = 20;
    }
    if (options.Parentheses === true && preparedInput < 0) {
        n *= -1;
        n = parseFloat(n.toFixed(12));
    }
    if (options.Abs) {
        n = Math.abs(n);
    }
    if (options.Truncate) {
        n = Math.trunc(n);
    }
    if (options.Ceiling) {
        n = Math.ceil(n);
    }
    if (options.Round) {
        n = Math.round(n);
    }
    if (options.Floor) {
        n = Math.floor(n);
    }
    let s;
    let digitsToUse;
    if (options.Truncate || options.Ceiling || options.Round || options.Floor) {
        digitsToUse = 0;
    }
    else if (options.FractionDigits != null) {
        digitsToUse = options.FractionDigits;
    }
    else {
        let decimalCount = Math.floor(n) === n ? 0 : n.toString().split(fractionsSepatator)[1]?.length || 0;
        digitsToUse = decimalCount;
    }
    s = n.toLocaleString('en-US', {
        minimumIntegerDigits: options.IntegerDigits || undefined,
        minimumFractionDigits: digitsToUse,
        maximumFractionDigits: digitsToUse,
    });
    if (options.FractionSeparator !== undefined) {
        s = s.replace(/\./g, options.FractionSeparator);
    }
    if (options.IntegerSeparator !== undefined) {
        s = s.replace(/\,/g, options.IntegerSeparator);
    }
    s = (options.Prefix || '') + s + (options.Suffix || '');
    if (options.Parentheses === true && preparedInput < 0) {
        s = '(' + s + ')';
    }
    return s;
}
export function DateFormatter(input, options, strictFormatting = false) {
    if (input == null || input == undefined || input == 'Invalid Date') {
        return undefined;
    }
    try {
        // not sure if this is right if using a custom formatter...
        if (typeof input === 'string') {
            input = new Date(input);
        }
        return dateFnsFormat(input, options?.Pattern || DEFAULT_DATE_FORMAT_PATTERN);
    }
    catch (error) {
        if (strictFormatting) {
            return `Invalid date formatting pattern`;
        }
        if (typeof input !== 'string') {
            return String(input);
        }
        return input;
    }
}
export function StringFormatter(input, options = {}, rowNode, column, api) {
    let normalisedTextInput = input;
    if (input != undefined && typeof input !== 'string') {
        const warningMessage = column
            ? `StringFormatter: input '${input}' from column ${column.columnId} (${column.dataType}) is not a string, but a ${typeof input}`
            : `StringFormatter: input '${input}' is not a string, received ${typeof input}`;
        if (api) {
            api.logWarn(warningMessage);
        }
        else {
            console.warn(warningMessage);
        }
        normalisedTextInput = `${input}`;
    }
    let preparedInput;
    if (options.Content) {
        const context = {
            column,
            rowNode,
            input: normalisedTextInput,
            api,
        };
        preparedInput = formatPlaceholder(options.Content, context);
    }
    else {
        preparedInput = normalisedTextInput;
    }
    if (StringExtensions.IsNullOrEmptyOrWhiteSpace(preparedInput)) {
        return undefined;
    }
    if (options.Empty) {
        return ' ';
    }
    let s = preparedInput;
    if (options.Prefix !== undefined) {
        s = options.Prefix + s;
    }
    if (options.Suffix !== undefined) {
        s = s + options.Suffix;
    }
    if (options.Case !== undefined) {
        if (options.Case == 'Lower') {
            s = s.toLowerCase();
        }
        else if (options.Case == 'Upper') {
            s = s.toUpperCase();
        }
        else if (options.Case == 'Sentence') {
            s = sentenceCase(s);
        }
    }
    if (options.Trim !== undefined && options.Trim == true) {
        s = s.trim();
    }
    return s;
}
function formatPlaceholder(text, context) {
    if (!text) {
        return text;
    }
    if (!context) {
        return text;
    }
    if (context?.input) {
        text = Helper.replaceAll(text, '[value]', context.input);
    }
    if (context?.column) {
        text = Helper.replaceAll(text, '[column]', context.api.columnApi.getFriendlyNameForColumnId(context.column.columnId));
    }
    if (context?.rowNode) {
        const columns = Helper.extractColsFromText(text);
        for (const column of columns) {
            if (context.api.columnApi.getColumnWithColumnId(column)) {
                text = Helper.replaceAll(text, `[rowData.${column}]`, context.api.gridApi.getRawValueFromRowNode(context.rowNode, column));
            }
        }
    }
    return text;
}
export default { NumberFormatter, DateFormatter, StringFormatter };
