/**
 * Converts parsed log query tokens into a Query<Log> object compatible with
 * the AnalyticsDatabaseService query system.
 */
import { TokenType, FilterOperator, parseLogQuery, } from "./LogQueryParser";
import Search from "../BaseDatabase/Search";
import NotEqual from "../BaseDatabase/NotEqual";
import GreaterThan from "../BaseDatabase/GreaterThan";
import GreaterThanOrEqual from "../BaseDatabase/GreaterThanOrEqual";
import LessThan from "../BaseDatabase/LessThan";
import LessThanOrEqual from "../BaseDatabase/LessThanOrEqual";
const TOP_LEVEL_FIELDS = new Set([
    "severityText",
    "primaryEntityId",
    "traceId",
    "spanId",
    "body",
]);
/*
 * Severity values stored in the database use title case (e.g. "Error", "Debug").
 * Normalise user input so that "error" matches "Error", etc.
 */
const SEVERITY_CANONICAL = {
    fatal: "Fatal",
    error: "Error",
    warning: "Warning",
    warn: "Warning",
    information: "Information",
    info: "Information",
    debug: "Debug",
    trace: "Trace",
    unspecified: "Unspecified",
};
function normalizeSeverityValue(value) {
    return SEVERITY_CANONICAL[value.toLowerCase()] || value;
}
function applyFieldFilter(filter, token) {
    if (!token.field) {
        return;
    }
    let value = token.value;
    // Normalise severity values to match database casing
    if (token.field === "severityText") {
        value = normalizeSeverityValue(value);
    }
    if (TOP_LEVEL_FIELDS.has(token.field)) {
        applyTopLevelFilter(filter, token.field, value, token.operator);
    }
    else {
        applyAttributeFilter(filter, token.field, value, token.operator);
    }
}
function applyTopLevelFilter(filter, field, value, operator) {
    switch (operator) {
        case FilterOperator.Contains:
        case FilterOperator.Wildcard:
            filter[field] = new Search(value.replace(/\*/g, ""));
            break;
        case FilterOperator.GreaterThan:
            filter[field] = new GreaterThan(parseNumericOrString(value));
            break;
        case FilterOperator.GreaterThanOrEqual:
            filter[field] = new GreaterThanOrEqual(parseNumericOrString(value));
            break;
        case FilterOperator.LessThan:
            filter[field] = new LessThan(parseNumericOrString(value));
            break;
        case FilterOperator.LessThanOrEqual:
            filter[field] = new LessThanOrEqual(parseNumericOrString(value));
            break;
        case FilterOperator.NotEquals:
            filter[field] = new NotEqual(value);
            break;
        case FilterOperator.Equals:
        default:
            filter[field] = value;
            break;
    }
}
function applyAttributeFilter(filter, field, value, operator) {
    if (!filter.attributes) {
        filter.attributes = {};
    }
    switch (operator) {
        case FilterOperator.Contains:
        case FilterOperator.Wildcard:
            filter.attributes[field] = new Search(value.replace(/\*/g, ""));
            break;
        case FilterOperator.NotEquals:
            filter.attributes[field] = new NotEqual(value);
            break;
        case FilterOperator.GreaterThan:
            filter.attributes[field] = new GreaterThan(parseNumericOrString(value));
            break;
        case FilterOperator.GreaterThanOrEqual:
            filter.attributes[field] = new GreaterThanOrEqual(parseNumericOrString(value));
            break;
        case FilterOperator.LessThan:
            filter.attributes[field] = new LessThan(parseNumericOrString(value));
            break;
        case FilterOperator.LessThanOrEqual:
            filter.attributes[field] = new LessThanOrEqual(parseNumericOrString(value));
            break;
        case FilterOperator.Equals:
        default:
            filter.attributes[field] = value;
            break;
    }
}
function applyFreeTextFilter(filter, token) {
    if (filter.body && filter.body instanceof Search) {
        const existing = filter.body.toString();
        filter.body = new Search(`${existing} ${token.value}`);
    }
    else if (filter.body && typeof filter.body === "string") {
        filter.body = new Search(`${filter.body} ${token.value}`);
    }
    else {
        filter.body = new Search(token.value);
    }
}
function parseNumericOrString(value) {
    const num = Number(value);
    return isNaN(num) ? value : num;
}
export function queryStringToFilter(queryString) {
    const tokens = parseLogQuery(queryString);
    const filter = {};
    for (const token of tokens) {
        switch (token.type) {
            case TokenType.FreeText:
                applyFreeTextFilter(filter, token);
                break;
            case TokenType.FieldFilter:
                applyFieldFilter(filter, token);
                break;
            case TokenType.AttributeFilter:
                applyFieldFilter(filter, token);
                break;
        }
    }
    return filter;
}
export default queryStringToFilter;
//# sourceMappingURL=LogQueryToFilter.js.map