import { uiDateToApi } from './dateHelper.js';

// ------------------------------------------
// Normalization
// ------------------------------------------
/**
 * Normalizes a querystring parameter into a consistent string array.
 *
 * Needed because Express/qs may return repeated query params as strings, arrays,
 * or numeric‑keyed objects depending on parser settings and arrayLimit behavior
 *
 * @param value The raw query parameter value from req.query.
 * @returns An array of strings representing the normalized parameter.
 */
const normalizeQueryStringArray = (queryParamValue) => {
    if (queryParamValue == null)
        return undefined;
    if (Array.isArray(queryParamValue))
        return queryParamValue;
    if (typeof queryParamValue === 'object') {
        const obj = queryParamValue;
        const numericKeys = Object.keys(obj)
            .filter((k) => /^\d+$/.test(k))
            .sort((a, b) => Number(a) - Number(b));
        return numericKeys.length > 0 ? numericKeys.map((k) => obj[k]) : undefined;
    }
    return typeof queryParamValue === 'string' ? [queryParamValue] : undefined;
};
// ------------------------------------------
// Parsing
// ------------------------------------------
const DEFAULT_EXCLUDED_KEYS = new Set([
    '_csrf',
    'reportName',
    'name',
    'reportId',
    'id',
    'description',
    'type',
    'sections',
]);
/**
 * Converts a querystring to a query object
 *
 * @param {string} qs
 * @param {string} prefix
 * @return {*}  {(Record<string, string | string[]>)}
 */
const qsToQueryObject = (qs, prefix) => {
    return Array.from(new URLSearchParams(qs).entries())
        .filter(([key]) => (prefix ? key.startsWith(prefix) : true))
        .reduce((acc, [key, value]) => {
        const existing = acc[key];
        if (existing === undefined) {
            acc[key] = value;
        }
        else if (Array.isArray(existing)) {
            acc[key] = [...existing, value];
        }
        else {
            acc[key] = [existing, value];
        }
        return acc;
    }, {});
};
/**
 * Converts a query obect back to a querystring
 *
 * @param {(Record<string, string | string[]>)} query
 * @return {*}  {string}
 */
const queryObjectToQs = (source, exclude = DEFAULT_EXCLUDED_KEYS) => {
    return Object.entries(source)
        .filter(([key]) => !exclude.has(key))
        .flatMap(([key, value]) => Array.isArray(value)
        ? value.map((v) => [key, normaliseUiDateIfPresent(v)])
        : [[key, normaliseUiDateIfPresent(value)]])
        .reduce((params, [key, value]) => {
        params.append(key, value);
        return params;
    }, new URLSearchParams())
        .toString();
};
const UI_DATE_REGEX = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
const normaliseUiDateIfPresent = (value) => {
    if (!UI_DATE_REGEX.test(value)) {
        return value;
    }
    return uiDateToApi(value) ?? value;
};
/**
 * Extracts `filters.*` entries from a query object.
 */
const extractFiltersFromQuery = (query) => {
    return Object.fromEntries(Object.entries(query).filter(([key]) => key.startsWith('filters.')));
};
/**
 * Given a form request body, will strip out the
 * 'filters.' prefix to return the field name/id and value
 *
 * @param {Record<string, unknown>} body
 * @return {*}  {Record<string, unknown>}
 */
const extractFiltersFromBody = (body) => {
    const result = {};
    Object.entries(body).forEach(([key, value]) => {
        if (!key.startsWith('filters.'))
            return;
        const path = key.replace('filters.', '').split('.');
        let current = result;
        path.forEach((segment, index) => {
            const isLast = index === path.length - 1;
            if (isLast) {
                current[segment] = value;
                return;
            }
            if (typeof current[segment] !== 'object' || current[segment] === null) {
                current[segment] = {};
            }
            current = current[segment];
        });
    });
    return result;
};
const getQueryParamAsString = (query, name) => query[name] ? query[name].toString() : null;
// ------------------------------------------
// UI to API adapters
// ------------------------------------------
/**
 * Builds a query string from a form body
 *
 * @param {Record<string, unknown>} body
 * @param {Set<string>} [exclude=new Set()]
 * @return {*}  {string}
 */
const formBodyToQs = (body, exclude = DEFAULT_EXCLUDED_KEYS) => {
    const params = new URLSearchParams();
    Object.entries(body).forEach(([key, value]) => {
        if (exclude.has(key))
            return;
        if (value == null || value === '')
            return;
        if (Array.isArray(value)) {
            const values = value.filter((v) => v != null && v !== '').map((v) => normaliseUiDateIfPresent(String(v)));
            if (values.length > 0) {
                params.set(key, values.join(','));
            }
            return;
        }
        params.set(key, normaliseUiDateIfPresent(String(value)));
    });
    return params.toString();
};
/**
 * Converts a form body to an API query object
 * - Excludes specified keys
 * - Drops null / empty values
 * - Collapses arrays to CSV (BE contract)
 *
 * @param {Record<string, unknown>} body
 * @return {*}  {(Record<string, string | string[]>)}
 */
const formBodyToQueryObject = (body, exclude = DEFAULT_EXCLUDED_KEYS) => {
    return Object.entries(body).reduce((acc, [key, value]) => {
        if (exclude.has(key))
            return acc;
        if (value === undefined || value === null || value === '')
            return acc;
        if (Array.isArray(value)) {
            const values = value.filter((v) => v != null && v !== '').map((v) => normaliseUiDateIfPresent(String(v)));
            if (values.length > 0) {
                acc[key] = values.join(',');
            }
            return acc;
        }
        acc[key] = normaliseUiDateIfPresent(String(value));
        return acc;
    }, {});
};

export { extractFiltersFromBody, extractFiltersFromQuery, formBodyToQs, formBodyToQueryObject, getQueryParamAsString, normalizeQueryStringArray, qsToQueryObject, queryObjectToQs };
//# sourceMappingURL=queryMappers.js.map
