// (C) 2025 GoodData Corporation
import { ClientFormatterFacade } from "@gooddata/number-formatter";
const DEFAULT_SAMPLE_VALUE = 12345.67;
const DEFAULT_REQUIRED_DECIMALS = 2;
const SECTION_SEPARATOR = ";";
const NUMBER_PLACEHOLDER_PATTERN = /[0#?]/;
const DECIMAL_TOKEN_PATTERN = /\.(0+)/;
const CURRENCY_SYMBOL_PATTERN = /\p{Sc}/u;
const CURRENCY_BRACKET_PATTERN = /\[\$[^\]]+\]/;
const QUOTED_CURRENCY_PATTERN = /(["'])[ \t]*[A-Za-z]{2,6}[ \t]*\1/;
const DEFAULT_ERROR_MESSAGES = {
    empty: "Format is required.",
    invalidFormat: "Format contains invalid tokens.",
    missingCurrencySymbol: "Currency symbol is missing.",
    missingDecimalPlaces: "Format must include the required decimal places.",
};
/**
 * Validates a number format string that is expected to represent a currency amount.
 *
 * @alpha
 */
export function validateCurrencyFormat(format, options = {}) {
    const sanitizedFormat = format?.trim() ?? "";
    const errors = [];
    if (!sanitizedFormat) {
        errors.push(buildError("empty"));
        return { isValid: false, errors };
    }
    const sampleValue = options.sampleValue ?? DEFAULT_SAMPLE_VALUE;
    const separators = options.separators;
    if (!isParsableFormat(sanitizedFormat, sampleValue, separators)) {
        errors.push(buildError("invalidFormat"));
        return { isValid: false, errors };
    }
    const sections = getFormatSections(sanitizedFormat);
    const sectionsWithNumbers = sections.filter(hasNumericPlaceholder);
    if (sectionsWithNumbers.length === 0) {
        errors.push(buildError("invalidFormat"));
        return { isValid: false, errors };
    }
    if (!sectionsWithNumbers.every(hasCurrencyToken)) {
        errors.push(buildError("missingCurrencySymbol", collectInvalidSections(sectionsWithNumbers, hasCurrencyToken)));
    }
    const requiredDecimals = options.requiredDecimalPlaces ?? DEFAULT_REQUIRED_DECIMALS;
    if (requiredDecimals > 0 &&
        !sectionsWithNumbers.every((section) => hasRequiredDecimals(section, requiredDecimals))) {
        errors.push(buildError("missingDecimalPlaces", collectInvalidSections(sectionsWithNumbers, (section) => hasRequiredDecimals(section, requiredDecimals))));
    }
    return {
        isValid: errors.length === 0,
        errors,
    };
}
function buildError(code, sectionIndexes) {
    return {
        code,
        sectionIndexes,
        message: DEFAULT_ERROR_MESSAGES[code],
    };
}
function getFormatSections(format) {
    return format
        .split(SECTION_SEPARATOR)
        .map((section) => section.trim())
        .filter((section) => section.length > 0);
}
function hasNumericPlaceholder(section) {
    return NUMBER_PLACEHOLDER_PATTERN.test(section);
}
function hasCurrencyToken(section) {
    return (CURRENCY_BRACKET_PATTERN.test(section) ||
        CURRENCY_SYMBOL_PATTERN.test(section) ||
        QUOTED_CURRENCY_PATTERN.test(section));
}
function hasRequiredDecimals(section, requiredDecimalPlaces) {
    const match = section.match(DECIMAL_TOKEN_PATTERN);
    if (!match) {
        return false;
    }
    return match[1].length >= requiredDecimalPlaces;
}
function collectInvalidSections(sections, predicate) {
    const invalidIndexes = sections.reduce((result, section, index) => {
        if (!predicate(section)) {
            result.push(index);
        }
        return result;
    }, []);
    return invalidIndexes.length > 0 ? invalidIndexes : undefined;
}
function isParsableFormat(format, sampleValue, separators) {
    try {
        ClientFormatterFacade.formatValue(sampleValue, format, separators);
        return true;
    }
    catch {
        return false;
    }
}
/**
 * Checks if a format string represents a currency format.
 * A currency format is one where at least one numeric section contains a currency symbol.
 *
 * @alpha
 */
export function isCurrencyFormat(format) {
    const sanitizedFormat = format?.trim();
    if (!sanitizedFormat) {
        return false;
    }
    const sections = getFormatSections(sanitizedFormat);
    const sectionsWithNumbers = sections.filter(hasNumericPlaceholder);
    if (sectionsWithNumbers.length === 0) {
        return false;
    }
    return sectionsWithNumbers.some(hasCurrencyToken);
}
