"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFilterQueryParam = getFilterQueryParam;
exports.formatFilterBlock = formatFilterBlock;
exports.formatPredicate = formatPredicate;
const isNilOrEmptyString_1 = require("../commonHelpers/isNilOrEmptyString");
function getFilterQueryParam(query) {
    return query.filters
        .map(formatFilterBlock)
        .filter(removeEmptyClauses)
        .join(" AND ");
}
function formatFilterBlock(filter) {
    const operation = filter.operation || "OR";
    const formatted = filter.predicates
        .map(formatPredicate)
        .filter(removeEmptyClauses)
        .join(` ${operation} `);
    return `(${formatted})`;
}
function formatPredicate(predicate) {
    const formatted = Object.entries(predicate)
        // Remove predicates that use `term` (handled in `getQQueryParam`),
        // `bbox` (handled in `getBboxQueryParam),
        // `fields` (handled in `getFieldsQueryParam)
        // `flatten` (handled in `getFlattenQueryParam) or have undefined entries
        .filter(([field, value]) => field !== "term" &&
        field !== "bbox" &&
        field !== "fields" &&
        field !== "flatten" &&
        !(0, isNilOrEmptyString_1.isNilOrEmptyString)(value))
        // Create sections for each field
        .reduce((acc, [field, value]) => {
        let section;
        if (typeof value === "string" || typeof value === "boolean") {
            section = formatSimpleComparison(field, value);
        }
        else if (Array.isArray(value)) {
            section = formatMultiStringPredicate(field, value);
        }
        else if (isDateRange(value)) {
            section = formatDateRangePredicate(field, value);
        }
        else {
            section = formatComplexPredicate(field, value);
        }
        acc.push(section);
        return acc;
    }, [])
        // AND together all field requirements
        .join(" AND ");
    return `(${formatted})`;
}
function isDateRange(x) {
    return Number.isInteger(x.from) && Number.isInteger(x.to);
}
function formatDateRangePredicate(field, value) {
    return `${field} BETWEEN ${value.from} AND ${value.to}`;
}
function formatSimpleComparison(field, value) {
    const formattedValue = typeof value === "string" ? maybeAddSingleQuotes(value) : value;
    return `${field}=${formattedValue.toString()}`;
}
function formatMultiStringPredicate(field, values) {
    const wrappedValues = values.map(maybeAddSingleQuotes);
    return `${field} IN (${wrappedValues.join(", ")})`;
}
function formatComplexPredicate(field, value) {
    const anys = formatAnys(field, value.any);
    const alls = formatAlls(field, value.all);
    const nots = formatNots(field, value.not);
    return [anys, alls, nots].filter((subsection) => !!subsection).join(" AND ");
}
function formatAnys(field, value) {
    let result;
    if (Array.isArray(value)) {
        const wrappedValues = value.map(maybeAddSingleQuotes);
        result = `${field} IN (${wrappedValues.join(", ")})`;
    }
    else if (value) {
        result = formatSimpleComparison(field, value);
    }
    return result;
}
function formatAlls(field, value) {
    let result;
    if (Array.isArray(value)) {
        result = value
            .map((v) => formatSimpleComparison(field, v))
            .join(" AND ");
    }
    else if (value) {
        result = formatSimpleComparison(field, value);
    }
    return result;
}
function formatNots(field, value) {
    let result;
    if (value) {
        const valueAsArray = Array.isArray(value) ? value : [value];
        const wrappedValues = valueAsArray.map(maybeAddSingleQuotes);
        result = `${field} NOT IN (${wrappedValues.join(", ")})`;
    }
    return result;
}
function maybeAddSingleQuotes(value) {
    const whitespaceRegex = /\s/;
    return whitespaceRegex.test(value) ? `'${value}'` : value;
}
/**
 * Returns whether a clause is non-empty and should be included in the
 * final serialized string.
 *
 * Empty clauses appear when certain predicates are detected that are invalid
 * in the OGC API's ?filter string (i.e. `term`, `bbox`)
 *
 * @param clause stringified clause to inspect
 * @returns whether the clause should be included in the final serialization
 */
function removeEmptyClauses(clause) {
    return clause !== "()";
}
//# sourceMappingURL=getFilterQueryParam.js.map