"use strict";
/*
 * Copyright (c) 2021-2022.
 * Author Peter Placzek (tada5hi)
 * For the full copyright and license information,
 * view the LICENSE file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseQueryFilters = void 0;
const utils_1 = require("../../utils");
const fields_1 = require("../fields");
const utils_2 = require("../utils");
const constants_1 = require("./constants");
const utils_3 = require("./utils");
// --------------------------------------------------
function transformFiltersParseOutputElement(element) {
    if ((0, utils_1.hasOwnProperty)(element, 'path') &&
        (typeof element.path === 'undefined' || element.path === null)) {
        delete element.path;
    }
    if (element.operator) {
        return element;
    }
    if (typeof element.value === 'string') {
        element = Object.assign(Object.assign({}, element), (0, utils_3.parseFilterValue)(element.value));
    }
    else {
        element.operator = constants_1.FilterComparisonOperator.EQUAL;
    }
    element.value = (0, utils_3.transformFilterValue)(element.value);
    return element;
}
function buildDefaultFiltersParseOutput(options, input) {
    const inputKeys = Object.keys(input || {});
    if (!options.defaultByElement &&
        inputKeys.length > 0) {
        return Object.values(input);
    }
    if (options.default) {
        const flatten = (0, utils_1.flattenNestedObject)(options.default);
        const keys = Object.keys(flatten);
        const output = [];
        for (let i = 0; i < keys.length; i++) {
            const fieldDetails = (0, utils_1.getFieldDetails)(keys[i]);
            if (options.defaultByElement &&
                inputKeys.length > 0) {
                const fieldWithAlias = (0, utils_1.buildFieldWithPath)(fieldDetails);
                if ((0, utils_1.hasOwnProperty)(input, fieldWithAlias)) {
                    continue;
                }
            }
            if (options.defaultByElement || inputKeys.length === 0) {
                let path;
                if (fieldDetails.path) {
                    path = fieldDetails.path;
                }
                else if (options.defaultPath) {
                    path = options.defaultPath;
                }
                output.push(transformFiltersParseOutputElement(Object.assign(Object.assign({}, (path ? { path } : {})), { key: fieldDetails.name, value: flatten[keys[i]] })));
            }
        }
        return input ? [...Object.values(input), ...output] : output;
    }
    return input ? Object.values(input) : [];
}
function parseQueryFilters(data, options) {
    options = options !== null && options !== void 0 ? options : {};
    options.mapping = options.mapping || {};
    options.relations = options.relations || [];
    // If it is an empty array nothing is allowed
    if (typeof options.allowed !== 'undefined') {
        options.allowed = (0, utils_2.flattenParseAllowedOption)(options.allowed);
        if (options.allowed.length === 0) {
            return buildDefaultFiltersParseOutput(options);
        }
    }
    /* istanbul ignore next */
    if (typeof data !== 'object' || data === null) {
        return buildDefaultFiltersParseOutput(options);
    }
    const { length } = Object.keys(data);
    if (length === 0) {
        return buildDefaultFiltersParseOutput(options);
    }
    if ((typeof options.allowed === 'undefined' || options.allowed.length === 0) &&
        options.default) {
        const flatten = (0, utils_1.flattenNestedObject)(options.default);
        options.allowed = Object.keys(flatten);
    }
    const items = {};
    // transform to appreciate data format & validate input
    const keys = Object.keys(data);
    for (let i = 0; i < keys.length; i++) {
        /* istanbul ignore next */
        if (!(0, utils_1.hasOwnProperty)(data, keys[i])) {
            // eslint-disable-next-line no-continue
            continue;
        }
        const value = data[keys[i]];
        if (typeof value !== 'string' &&
            typeof value !== 'number' &&
            typeof value !== 'boolean' &&
            typeof value !== 'undefined' &&
            value !== null &&
            !Array.isArray(value)) {
            continue;
        }
        keys[i] = (0, utils_1.applyMapping)(keys[i], options.mapping);
        const fieldDetails = (0, utils_1.getFieldDetails)(keys[i]);
        if (typeof options.allowed === 'undefined' &&
            !(0, fields_1.isValidFieldName)(fieldDetails.name)) {
            continue;
        }
        if (!(0, utils_1.isFieldPathAllowedByRelations)(fieldDetails, options.relations) &&
            !(0, utils_1.isFieldNonRelational)(fieldDetails)) {
            continue;
        }
        const fullKey = (0, utils_1.buildFieldWithPath)(fieldDetails);
        if (options.allowed &&
            !(0, utils_2.isPathCoveredByParseAllowedOption)(options.allowed, [keys[i], fullKey])) {
            continue;
        }
        const filter = transformFiltersParseOutputElement({
            key: fieldDetails.name,
            value: value,
        });
        if (options.validate) {
            if (Array.isArray(filter.value)) {
                const output = [];
                for (let j = 0; j < filter.value.length; j++) {
                    if (options.validate(filter.key, filter.value[j])) {
                        output.push(filter.value[j]);
                    }
                }
                filter.value = output;
                if (filter.value.length === 0) {
                    continue;
                }
            }
            else if (!options.validate(filter.key, filter.value)) {
                continue;
            }
        }
        if (typeof filter.value === 'string' &&
            filter.value.length === 0) {
            continue;
        }
        if (Array.isArray(filter.value) &&
            filter.value.length === 0) {
            continue;
        }
        if (fieldDetails.path || options.defaultPath) {
            filter.path = fieldDetails.path || options.defaultPath;
        }
        items[fullKey] = filter;
    }
    return buildDefaultFiltersParseOutput(options, items);
}
exports.parseQueryFilters = parseQueryFilters;
//# sourceMappingURL=parse.js.map