import { FindVariableContext } from './ast-utils.js';
export function extractExpressionPrefixVariable(context, expression) {
    return extractExpressionPrefixVariableInternal(new FindVariableContext(context), expression);
}
export function extractExpressionPrefixLiteral(context, expression) {
    return extractExpressionPrefixLiteralInternal(new FindVariableContext(context), expression);
}
export function extractExpressionSuffixLiteral(context, expression) {
    return extractExpressionSuffixLiteralInternal(new FindVariableContext(context), expression);
}
// Variable prefix extraction
function extractExpressionPrefixVariableInternal(context, expression) {
    switch (expression.type) {
        case 'BinaryExpression':
            return extractBinaryExpressionPrefixVariable(context, expression);
        case 'Identifier':
            return extractVariablePrefixVariable(context, expression);
        case 'MemberExpression':
            return extractMemberExpressionPrefixVariable(expression);
        case 'TemplateLiteral':
            return extractTemplateLiteralPrefixVariable(context, expression);
        default:
            return null;
    }
}
function extractBinaryExpressionPrefixVariable(context, expression) {
    return expression.left.type !== 'PrivateIdentifier'
        ? extractExpressionPrefixVariableInternal(context, expression.left)
        : null;
}
function extractVariablePrefixVariable(context, expression) {
    const variable = context.findVariable(expression);
    if (variable === null ||
        variable.identifiers.length !== 1 ||
        variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
        variable.identifiers[0].parent.init === null) {
        return expression;
    }
    return (extractExpressionPrefixVariableInternal(context, variable.identifiers[0].parent.init) ??
        expression);
}
function extractMemberExpressionPrefixVariable(expression) {
    return expression.property.type === 'Identifier' ? expression.property : null;
}
function extractTemplateLiteralPrefixVariable(context, expression) {
    const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
    for (const part of literalParts) {
        if (part.type === 'TemplateElement' && part.value.raw === '') {
            // Skip empty quasi in the begining
            continue;
        }
        if (part.type !== 'TemplateElement') {
            return extractExpressionPrefixVariableInternal(context, part);
        }
        return null;
    }
    return null;
}
// Literal prefix extraction
function extractExpressionPrefixLiteralInternal(context, expression) {
    switch (expression.type) {
        case 'BinaryExpression':
            return extractBinaryExpressionPrefixLiteral(context, expression);
        case 'Identifier':
            return extractVariablePrefixLiteral(context, expression);
        case 'Literal':
            return typeof expression.value === 'string' ? expression.value : null;
        case 'SvelteLiteral':
            return expression.value;
        case 'TemplateLiteral':
            return extractTemplateLiteralPrefixLiteral(context, expression);
        default:
            return null;
    }
}
function extractBinaryExpressionPrefixLiteral(context, expression) {
    return expression.left.type !== 'PrivateIdentifier'
        ? extractExpressionPrefixLiteralInternal(context, expression.left)
        : null;
}
function extractVariablePrefixLiteral(context, expression) {
    const variable = context.findVariable(expression);
    if (variable === null ||
        variable.identifiers.length !== 1 ||
        variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
        variable.identifiers[0].parent.init === null) {
        return null;
    }
    return extractExpressionPrefixLiteralInternal(context, variable.identifiers[0].parent.init);
}
function extractTemplateLiteralPrefixLiteral(context, expression) {
    const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
    for (const part of literalParts) {
        if (part.type === 'TemplateElement') {
            if (part.value.raw === '') {
                // Skip empty quasi
                continue;
            }
            return part.value.raw;
        }
        return extractExpressionPrefixLiteralInternal(context, part);
    }
    return null;
}
// Literal suffix extraction
function extractExpressionSuffixLiteralInternal(context, expression) {
    switch (expression.type) {
        case 'BinaryExpression':
            return extractBinaryExpressionSuffixLiteral(context, expression);
        case 'Identifier':
            return extractVariableSuffixLiteral(context, expression);
        case 'Literal':
            return typeof expression.value === 'string' ? expression.value : null;
        case 'SvelteLiteral':
            return expression.value;
        case 'TemplateLiteral':
            return extractTemplateLiteralSuffixLiteral(context, expression);
        default:
            return null;
    }
}
function extractBinaryExpressionSuffixLiteral(context, expression) {
    return extractExpressionSuffixLiteralInternal(context, expression.right);
}
function extractVariableSuffixLiteral(context, expression) {
    const variable = context.findVariable(expression);
    if (variable === null ||
        variable.identifiers.length !== 1 ||
        variable.identifiers[0].parent.type !== 'VariableDeclarator' ||
        variable.identifiers[0].parent.init === null) {
        return null;
    }
    return extractExpressionSuffixLiteralInternal(context, variable.identifiers[0].parent.init);
}
function extractTemplateLiteralSuffixLiteral(context, expression) {
    const literalParts = [...expression.expressions, ...expression.quasis].sort((a, b) => a.range[0] < b.range[0] ? -1 : 1);
    for (const part of literalParts.reverse()) {
        if (part.type === 'TemplateElement') {
            if (part.value.raw === '') {
                // Skip empty quasi
                continue;
            }
            return part.value.raw;
        }
        return extractExpressionSuffixLiteralInternal(context, part);
    }
    return null;
}
