/**
 * LogQueryParser
 *
 * Parses a Datadog-style log search query string into structured filter tokens.
 *
 * Supported syntax:
 *   - Free text:           `connection refused`       → body ILIKE '%connection refused%'
 *   - Quoted phrase:       `"connection refused"`     → body ILIKE '%connection refused%'
 *   - Field-specific:      `severity:error`           → severityText = 'error'
 *   - Attribute access:    `@http.status_code:500`    → attributes.http.status_code = '500'
 *   - Negation (prefix):   `-severity:debug`          → severityText != 'debug'
 *   - Wildcard:            `service:api-*`            → primaryEntityId ILIKE 'api-%'
 *   - Numeric range:       `@duration:>1000`          → attributes.duration > 1000
 *   - Boolean:             `severity:error AND service:api` (AND is default between tokens)
 *
 * Produces an array of ParsedToken objects consumed by the search bar and query builder.
 */
export var TokenType;
(function (TokenType) {
    TokenType["FreeText"] = "FreeText";
    TokenType["FieldFilter"] = "FieldFilter";
    TokenType["AttributeFilter"] = "AttributeFilter";
})(TokenType || (TokenType = {}));
export var FilterOperator;
(function (FilterOperator) {
    FilterOperator["Equals"] = "Equals";
    FilterOperator["NotEquals"] = "NotEquals";
    FilterOperator["Contains"] = "Contains";
    FilterOperator["NotContains"] = "NotContains";
    FilterOperator["GreaterThan"] = "GreaterThan";
    FilterOperator["GreaterThanOrEqual"] = "GreaterThanOrEqual";
    FilterOperator["LessThan"] = "LessThan";
    FilterOperator["LessThanOrEqual"] = "LessThanOrEqual";
    FilterOperator["Wildcard"] = "Wildcard";
})(FilterOperator || (FilterOperator = {}));
const FIELD_ALIASES = {
    severity: "severityText",
    level: "severityText",
    service: "primaryEntityId",
    trace: "traceId",
    span: "spanId",
    message: "body",
    msg: "body",
    log: "body",
};
const BOOLEAN_KEYWORDS = new Set(["AND", "OR", "NOT"]);
function resolveFieldName(raw) {
    const lower = raw.toLowerCase();
    return FIELD_ALIASES[lower] || raw;
}
function detectOperator(value) {
    if (value.startsWith(">=")) {
        return {
            operator: FilterOperator.GreaterThanOrEqual,
            cleanValue: value.slice(2),
        };
    }
    if (value.startsWith("<=")) {
        return {
            operator: FilterOperator.LessThanOrEqual,
            cleanValue: value.slice(2),
        };
    }
    if (value.startsWith(">")) {
        return {
            operator: FilterOperator.GreaterThan,
            cleanValue: value.slice(1),
        };
    }
    if (value.startsWith("<")) {
        return {
            operator: FilterOperator.LessThan,
            cleanValue: value.slice(1),
        };
    }
    if (value.includes("*")) {
        return {
            operator: FilterOperator.Wildcard,
            cleanValue: value,
        };
    }
    return {
        operator: FilterOperator.Equals,
        cleanValue: value,
    };
}
function tokenizeRawInput(input) {
    const tokens = [];
    let current = "";
    let inQuotes = false;
    for (let i = 0; i < input.length; i++) {
        const char = input[i];
        if (char === '"') {
            inQuotes = !inQuotes;
            current += char;
            continue;
        }
        if (char === " " && !inQuotes) {
            if (current.length > 0) {
                tokens.push(current);
                current = "";
            }
            continue;
        }
        current += char;
    }
    if (current.length > 0) {
        tokens.push(current);
    }
    return tokens;
}
function stripQuotes(value) {
    if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
        return value.slice(1, -1);
    }
    return value;
}
function parseFieldToken(raw) {
    let workingRaw = raw;
    let negated = false;
    if (workingRaw.startsWith("-")) {
        negated = true;
        workingRaw = workingRaw.slice(1);
    }
    const isAttribute = workingRaw.startsWith("@");
    if (isAttribute) {
        workingRaw = workingRaw.slice(1);
    }
    const colonIndex = workingRaw.indexOf(":");
    if (colonIndex === -1) {
        return {
            type: TokenType.FreeText,
            operator: FilterOperator.Contains,
            value: stripQuotes(workingRaw),
            negated,
            raw,
        };
    }
    const rawField = workingRaw.slice(0, colonIndex);
    const rawValue = stripQuotes(workingRaw.slice(colonIndex + 1));
    const { operator, cleanValue } = detectOperator(rawValue);
    const field = isAttribute ? rawField : resolveFieldName(rawField);
    return {
        type: isAttribute ? TokenType.AttributeFilter : TokenType.FieldFilter,
        field,
        operator: negated && operator === FilterOperator.Equals
            ? FilterOperator.NotEquals
            : operator,
        value: cleanValue,
        negated,
        raw,
    };
}
export function parseLogQuery(query) {
    const trimmed = query.trim();
    if (trimmed.length === 0) {
        return [];
    }
    const rawTokens = tokenizeRawInput(trimmed);
    const tokens = [];
    const freeTextParts = [];
    const flushFreeText = () => {
        if (freeTextParts.length > 0) {
            const combined = freeTextParts.join(" ");
            tokens.push({
                type: TokenType.FreeText,
                operator: FilterOperator.Contains,
                value: combined,
                negated: false,
                raw: combined,
            });
            freeTextParts.length = 0;
        }
    };
    for (const rawToken of rawTokens) {
        if (BOOLEAN_KEYWORDS.has(rawToken)) {
            continue;
        }
        const hasColon = rawToken.includes(":") && !rawToken.startsWith('"');
        const isNegatedField = rawToken.startsWith("-") && rawToken.slice(1).includes(":");
        if (hasColon || isNegatedField) {
            flushFreeText();
            tokens.push(parseFieldToken(rawToken));
        }
        else {
            freeTextParts.push(stripQuotes(rawToken));
        }
    }
    flushFreeText();
    return tokens;
}
export function tokensToDisplayString(tokens) {
    return tokens
        .map((t) => {
        return t.raw;
    })
        .join(" ");
}
export default parseLogQuery;
//# sourceMappingURL=LogQueryParser.js.map