import { isBooleanAdaptableQlFunction } from '../../../Utilities/ExpressionFunctions/booleanExpressionFunctions';
import { getAST } from '../index';
import { isAST_Function } from '../types';
import { isQlLogicalOperator } from './types';
export const isArgumentColumnOrField = (arg) => {
    return arg && typeof arg === 'string' && (arg.includes('[') || arg.includes('FIELD'));
};
function mapAstToQlPredicate(ast) {
    const operator = getOperatorFromAST(ast);
    if (!isAST_Function(ast)) {
        return;
    }
    if (!operator || !isBooleanAdaptableQlFunction(operator)) {
        throw {
            errorMessage: `Only boolean functions are supported!`,
        };
    }
    const mapArgToPlArgs = (arg) => {
        if (typeof arg === 'object' && !Array.isArray(arg) && 'type' in arg) {
            if (arg.type === 'COL') {
                return [`[${arg.args[0]}]`];
            }
            // special case for FIELD
            if (arg.type === 'FIELD') {
                // we are keeping the expression to know we are dealing with a field
                return `FIELD('${arg.args[0]}')`;
            }
            if (arg.type === 'DATE') {
                return `DATE("${arg.args[0]}")`;
            }
            return mapAstToQlPredicate(arg);
        }
        if (['string', 'boolean', 'number'].includes(typeof arg)) {
            return arg;
        }
        if (arg && Array.isArray(arg)) {
            return arg.map((a) => mapArgToPlArgs(a)).flat();
        }
        return null;
    };
    const args = ast.args
        .map(mapArgToPlArgs)
        .filter((arg) => arg !== null && arg !== undefined)
        .flat();
    if (!isQlLogicalOperator(operator)) {
        // this throws
        if (!isArgumentColumnOrField(args[0])) {
            throw {
                errorMessage: 'First Argument must be an Adaptable Column or Field!',
            };
        }
    }
    return {
        operator,
        args,
    };
}
export function mapExpressionToQlPredicate(expression) {
    try {
        if (!expression) {
            // return a sensible default
            return {
                operator: 'AND',
                args: [],
            };
        }
        const ast = getAST(expression);
        const astRootNode = ast?.[0];
        // TEST IS ROOT
        if (!astRootNode || !isAST_Function(astRootNode)) {
            throw { errorMessage: `Invalid expression: ${expression}` };
        }
        const operator = getOperatorFromAST(astRootNode);
        if (!operator || !isBooleanAdaptableQlFunction(operator)) {
            return { errorMessage: `Only boolean functions are supported!` };
        }
        const inputs = astRootNode.args;
        const qlPredicate = mapAstToQlPredicate(astRootNode);
        if (!isQlLogicalOperator(qlPredicate.operator)) {
            return {
                operator: 'AND',
                args: [qlPredicate],
            };
        }
        else {
            return qlPredicate;
        }
    }
    catch (err) {
        return {
            errorMessage: `Query Builder does not support the expression: ${expression}`,
        };
    }
}
function getOperatorFromAST(astRootNode) {
    if (!['INFIX', 'FUNCTION', 'VALUE_REF'].includes(astRootNode.metaInfo)) {
        return undefined;
    }
    return astRootNode.type;
}
