// engine/code-transforms/typescript/modernize-syntax.ts — (AC-05).
// var->const/let, require->import, module.exports->export default, templates.
import { getTypeScript, parseSource, getLineNumber, createChange, replaceRange, } from './ast-utils.js';
// ---------------------------------------------------------------------------
// var -> const/let
// ---------------------------------------------------------------------------
function modernizeVar(ts, sourceFile, source) {
    const changes = [];
    const replacements = [];
    function visit(node) {
        if (ts.isVariableStatement(node)) {
            const declList = node.declarationList;
            const isConst = (declList.flags & ts.NodeFlags.Const) !== 0;
            const isLet = (declList.flags & ts.NodeFlags.Let) !== 0;
            if (isConst || isLet) {
                ts.forEachChild(node, visit);
                return;
            }
            const keyword = 'const';
            const start = declList.getStart(sourceFile);
            const varEnd = start + 3; // "var".length
            replacements.push({
                start,
                end: varEnd,
                text: keyword,
                line: getLineNumber(sourceFile, start),
            });
        }
        ts.forEachChild(node, visit);
    }
    visit(sourceFile);
    replacements.sort((a, b) => b.start - a.start);
    let result = source;
    for (const r of replacements) {
        result = replaceRange(result, r.start, r.end, r.text);
        changes.push(createChange(r.line, `Changed 'var' to '${r.text}'`));
    }
    changes.sort((a, b) => a.line - b.line);
    return { result, changes };
}
// ---------------------------------------------------------------------------
// require() -> import
// ---------------------------------------------------------------------------
function modernizeRequire(ts, sourceFile, source) {
    const changes = [];
    const replacements = [];
    function visit(node) {
        if (ts.isVariableStatement(node) && node.declarationList.declarations.length === 1) {
            const decl = node.declarationList.declarations[0];
            /* v8 ignore next 3 -- defensive: declarations[0] always exists when length === 1 */
            if (!decl) {
                return;
            }
            if (decl.initializer &&
                ts.isCallExpression(decl.initializer) &&
                ts.isIdentifier(decl.initializer.expression) &&
                decl.initializer.expression.text === 'require' &&
                decl.initializer.arguments.length === 1) {
                const arg = decl.initializer.arguments[0];
                if (arg && ts.isStringLiteral(arg)) {
                    const name = decl.name.getText(sourceFile);
                    const mod = arg.text;
                    const importStmt = `import ${name} from '${mod}';`;
                    const stmtStart = node.getStart(sourceFile);
                    const stmtEnd = node.getEnd();
                    replacements.push({
                        start: stmtStart,
                        end: stmtEnd,
                        text: importStmt,
                        line: getLineNumber(sourceFile, stmtStart),
                    });
                }
            }
        }
        ts.forEachChild(node, visit);
    }
    visit(sourceFile);
    replacements.sort((a, b) => b.start - a.start);
    let result = source;
    for (const r of replacements) {
        result = replaceRange(result, r.start, r.end, r.text);
        changes.push(createChange(r.line, `Converted require() to import`));
    }
    changes.sort((a, b) => a.line - b.line);
    return { result, changes };
}
// ---------------------------------------------------------------------------
// module.exports -> export default
// ---------------------------------------------------------------------------
function modernizeModuleExports(ts, sourceFile, source) {
    const changes = [];
    const replacements = [];
    function visit(node) {
        if (ts.isExpressionStatement(node) &&
            ts.isBinaryExpression(node.expression) &&
            ts.isPropertyAccessExpression(node.expression.left) &&
            ts.isIdentifier(node.expression.left.expression) &&
            node.expression.left.expression.text === 'module' &&
            node.expression.left.name.text === 'exports') {
            const rhs = node.expression.right.getText(sourceFile);
            const stmtStart = node.getStart(sourceFile);
            const stmtEnd = node.getEnd();
            replacements.push({
                start: stmtStart,
                end: stmtEnd,
                text: `export default ${rhs};`,
                line: getLineNumber(sourceFile, stmtStart),
            });
        }
        ts.forEachChild(node, visit);
    }
    visit(sourceFile);
    replacements.sort((a, b) => b.start - a.start);
    let result = source;
    for (const r of replacements) {
        result = replaceRange(result, r.start, r.end, r.text);
        changes.push(createChange(r.line, `Converted module.exports to export default`));
    }
    changes.sort((a, b) => a.line - b.line);
    return { result, changes };
}
// ---------------------------------------------------------------------------
// String concatenation -> template literals
// ---------------------------------------------------------------------------
function isStringConcat(ts, node) {
    if (!ts.isBinaryExpression(node)) {
        return false;
    }
    if (node.operatorToken.kind !== ts.SyntaxKind.PlusToken) {
        return false;
    }
    const hasStr = ts.isStringLiteral(node.left) || ts.isStringLiteral(node.right);
    const hasNested = isStringConcat(ts, node.left) || isStringConcat(ts, node.right);
    return hasStr || hasNested;
}
function flattenConcat(ts, node, sourceFile) {
    if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
        return [
            ...flattenConcat(ts, node.left, sourceFile),
            ...flattenConcat(ts, node.right, sourceFile),
        ];
    }
    if (ts.isStringLiteral(node)) {
        return [node.text];
    }
    return [`\${${node.getText(sourceFile)}}`];
}
function modernizeTemplateLiterals(ts, sourceFile, source) {
    const changes = [];
    const replacements = [];
    function visit(node) {
        if (isStringConcat(ts, node)) {
            // Only process top-level concatenation
            if (isStringConcat(ts, node.parent)) {
                return;
            }
            const parts = flattenConcat(ts, node, sourceFile);
            const template = '`' + parts.join('') + '`';
            const start = node.getStart(sourceFile);
            const end = node.getEnd();
            replacements.push({
                start,
                end,
                text: template,
                line: getLineNumber(sourceFile, start),
            });
        }
        ts.forEachChild(node, visit);
    }
    visit(sourceFile);
    replacements.sort((a, b) => b.start - a.start);
    let result = source;
    for (const r of replacements) {
        result = replaceRange(result, r.start, r.end, r.text);
        changes.push(createChange(r.line, `Converted string concatenation to template literal`));
    }
    changes.sort((a, b) => a.line - b.line);
    return { result, changes };
}
// ---------------------------------------------------------------------------
// Main export
// ---------------------------------------------------------------------------
export function modernizeSyntax(source, options, fileName) {
    const ts = getTypeScript();
    const allChanges = [];
    let result = source;
    if (options.varToConst !== false) {
        const sf = parseSource(result, fileName);
        const r = modernizeVar(ts, sf, result);
        result = r.result;
        allChanges.push(...r.changes);
    }
    if (options.requireToImport !== false) {
        const sf = parseSource(result, fileName);
        const r = modernizeRequire(ts, sf, result);
        result = r.result;
        allChanges.push(...r.changes);
    }
    if (options.moduleExportsToExport !== false) {
        const sf = parseSource(result, fileName);
        const r = modernizeModuleExports(ts, sf, result);
        result = r.result;
        allChanges.push(...r.changes);
    }
    if (options.templateLiterals !== false) {
        const sf = parseSource(result, fileName);
        const r = modernizeTemplateLiterals(ts, sf, result);
        result = r.result;
        allChanges.push(...r.changes);
    }
    return { transformed: result, changes: allChanges };
}
//# sourceMappingURL=modernize-syntax.js.map