import { parseExpressionAt } from 'acorn';
const ACORN_OPTIONS = {
    ecmaVersion: 'latest',
    sourceType: 'module',
};
export function parseCallExpressionFragment(raw) {
    const trimmed = raw.trim();
    const openParen = trimmed.indexOf('(');
    if (openParen === -1 || !trimmed.endsWith(')')) {
        return null;
    }
    const prefix = trimmed.slice(0, openParen).trim();
    if (!prefix) {
        throw new Error('Expected a tool name before the argument list.');
    }
    const argsPortion = trimmed.slice(openParen + 1, -1);
    const trimmedArgs = argsPortion.trim();
    const attempts = buildParseAttempts(trimmedArgs);
    let callExpression;
    let parseError;
    for (const candidate of attempts) {
        try {
            const expression = parseExpressionAt(`__call${candidate}`, 0, ACORN_OPTIONS);
            if (expression.type === 'CallExpression') {
                callExpression = expression;
                break;
            }
        }
        catch (error) {
            parseError = error instanceof Error ? error : new Error(String(error));
        }
    }
    if (!callExpression) {
        const message = parseError?.message ?? 'Unexpected token';
        throw new Error(`Unable to parse call expression: ${message}`);
    }
    if (callExpression.arguments.length === 0) {
        return {
            ...splitPrefix(prefix),
            args: {},
        };
    }
    if (callExpression.arguments.length === 1 && callExpression.arguments[0]?.type === 'ObjectExpression') {
        const argument = callExpression.arguments[0];
        if (!argument || argument.type !== 'ObjectExpression') {
            throw new Error('Function-call syntax requires named arguments (e.g. issueId: 123).');
        }
        const args = extractObject(argument);
        return { ...splitPrefix(prefix), args };
    }
    // At this point we know the call expression isn't a plain object literal, so we interpret
    // whatever arguments remain positionally. We still reuse the literal extractor so nested
    // arrays/objects stay supported.
    const positionalArgs = callExpression.arguments.map((argument) => {
        if (!argument) {
            throw new Error('Unsupported empty argument in call expression.');
        }
        if (argument.type === 'SpreadElement') {
            throw new Error('Spread elements are not supported in call expressions.');
        }
        if (!isSupportedValue(argument)) {
            throw new Error(`Unsupported argument expression: ${argument.type}.`);
        }
        return extractValue(argument);
    });
    return { ...splitPrefix(prefix), args: {}, positionalArgs };
}
function splitPrefix(prefix) {
    const [first, ...rest] = prefix.split('.');
    if (!first) {
        throw new Error('Expected a tool name before the argument list.');
    }
    if (rest.length === 0) {
        return { tool: first };
    }
    return { server: first, tool: rest.join('.') };
}
function extractObject(expression) {
    const result = {};
    for (const property of expression.properties) {
        if (property.type !== 'Property') {
            throw new Error('Unsupported property type in call expression.');
        }
        if (property.kind !== 'init') {
            throw new Error('Only simple assignments are supported in call expressions.');
        }
        if (property.computed) {
            throw new Error('Computed property names are not supported in call expressions.');
        }
        const key = extractKey(property);
        const rawValue = property.value;
        if (!rawValue || !isSupportedValue(rawValue)) {
            throw new Error(`Unsupported argument expression: ${rawValue ? rawValue.type : 'null'}.`);
        }
        const value = extractValue(rawValue);
        result[key] = value;
    }
    return result;
}
function extractKey(property) {
    if (property.key.type === 'Identifier') {
        return property.key.name;
    }
    if (property.key.type === 'Literal' && typeof property.key.value === 'string') {
        return property.key.value;
    }
    throw new Error('Invalid argument name in call expression.');
}
function extractValue(value) {
    switch (value.type) {
        case 'Literal':
            return value.value ?? null;
        case 'ArrayExpression':
            return extractArray(value);
        case 'ObjectExpression':
            return extractObject(value);
        case 'UnaryExpression':
            return extractUnary(value);
        default:
            throw new Error(`Unsupported argument expression: ${value.type}.`);
    }
}
function extractArray(arrayExpression) {
    return arrayExpression.elements.map((element, index) => {
        if (!element) {
            throw new Error(`Sparse array entries are not supported (index ${index}).`);
        }
        if (element.type === 'SpreadElement') {
            throw new Error('Spread elements are not supported in call expressions.');
        }
        const elementType = element.type ?? 'unknown';
        if (!isSupportedValue(element)) {
            throw new Error(`Unsupported argument expression: ${elementType}.`);
        }
        return extractValue(element);
    });
}
function extractUnary(expression) {
    if (expression.operator === '-' || expression.operator === '+') {
        const inner = expression.argument;
        if (inner.type !== 'Literal' || typeof inner.value !== 'number') {
            throw new Error('Unary operators are only supported for numeric literals.');
        }
        const numericValue = Number(inner.value);
        return expression.operator === '-' ? -numericValue : numericValue;
    }
    if (expression.operator === '!') {
        const inner = expression.argument;
        if (inner.type !== 'Literal' || typeof inner.value !== 'boolean') {
            throw new Error('Logical negation is only supported for boolean literals.');
        }
        return !inner.value;
    }
    throw new Error(`Unsupported unary operator: ${expression.operator}`);
}
function buildParseAttempts(trimmedArgs) {
    if (trimmedArgs === '') {
        return ['()'];
    }
    const attempts = [`(${trimmedArgs})`];
    const needsObjectWrap = !trimmedArgs.startsWith('{') &&
        !trimmedArgs.startsWith('({') &&
        !trimmedArgs.startsWith('[') &&
        /[A-Za-z0-9_]\s*:/.test(trimmedArgs);
    if (needsObjectWrap) {
        attempts.push(`({${trimmedArgs}})`);
    }
    return attempts;
}
function isSupportedValue(node) {
    if (!node || typeof node !== 'object' || !('type' in node)) {
        return false;
    }
    const type = node.type;
    return type === 'Literal' || type === 'ArrayExpression' || type === 'ObjectExpression' || type === 'UnaryExpression';
}
//# sourceMappingURL=call-expression-parser.js.map