import * as fs from "node:fs";
import * as ts from "typescript";
const readEntityNameText = (name) => {
    if (ts.isIdentifier(name)) {
        return name.text;
    }
    if (ts.isQualifiedName(name)) {
        return `${readEntityNameText(name.left)}.${name.right.text}`;
    }
    if (ts.isPropertyAccessExpression(name)) {
        return `${readEntityNameText(name.expression)}.${name.name.text}`;
    }
    return ts.isStringLiteral(name) ? name.text : name.getText();
};
const getScriptKindFromPath = (filePath) => {
    if (filePath.endsWith(".ts") || filePath.endsWith(".d.ts")) {
        return ts.ScriptKind.TS;
    }
    if (filePath.endsWith(".mts") ||
        filePath.endsWith(".d.mts") ||
        filePath.endsWith(".cts") ||
        filePath.endsWith(".d.cts")) {
        return ts.ScriptKind.TS;
    }
    return ts.ScriptKind.Unknown;
};
const collectAliasTargets = (statements) => {
    const targets = [];
    for (const statement of statements) {
        if (ts.isExportDeclaration(statement) &&
            statement.moduleSpecifier &&
            ts.isStringLiteral(statement.moduleSpecifier)) {
            targets.push(statement.moduleSpecifier.text);
        }
    }
    return targets;
};
const collectFromModuleDeclaration = (node, aliases, declarationFile) => {
    if (!ts.isStringLiteral(node.name) || !node.body) {
        return;
    }
    let body = node.body;
    while (body && ts.isModuleDeclaration(body)) {
        body = body.body;
    }
    if (!body || !ts.isModuleBlock(body)) {
        return;
    }
    const targets = Array.from(new Set(collectAliasTargets(body.statements)));
    if (targets.length !== 1) {
        return;
    }
    const targetSpecifier = targets[0];
    if (!targetSpecifier) {
        return;
    }
    aliases.set(node.name.text, {
        targetSpecifier,
        declarationFile,
    });
};
export const discoverDeclarationModuleAliases = (declarationFiles) => {
    const aliases = new Map();
    for (const declarationFile of declarationFiles) {
        let sourceText;
        try {
            sourceText = fs.readFileSync(declarationFile, "utf-8");
        }
        catch {
            continue;
        }
        const sourceFile = ts.createSourceFile(declarationFile, sourceText, ts.ScriptTarget.Latest, false, getScriptKindFromPath(declarationFile));
        const visit = (node) => {
            if (ts.isModuleDeclaration(node)) {
                collectFromModuleDeclaration(node, aliases, declarationFile);
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
    }
    return aliases;
};
const collectAmbientGlobalImportsFromNode = (node, declarationFile, imports) => {
    if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name)) {
        return;
    }
    const typeNode = node.type;
    if (!typeNode || !ts.isImportTypeNode(typeNode) || !typeNode.isTypeOf) {
        return;
    }
    const argument = ts.isLiteralTypeNode(typeNode.argument) &&
        ts.isStringLiteral(typeNode.argument.literal)
        ? typeNode.argument.literal
        : undefined;
    if (!argument) {
        return;
    }
    const exportName = typeNode.qualifier
        ? readEntityNameText(typeNode.qualifier).trim()
        : undefined;
    if (!exportName) {
        return;
    }
    let current = node.parent;
    let isAmbientGlobal = false;
    while (current) {
        if (ts.isModuleDeclaration(current) &&
            ts.isIdentifier(current.name) &&
            current.name.text === "global") {
            isAmbientGlobal = true;
            break;
        }
        current = current.parent;
    }
    if (!isAmbientGlobal) {
        return;
    }
    imports.push({
        globalName: node.name.text,
        targetSpecifier: argument.text,
        exportName,
        declarationFile,
    });
};
export const discoverDeclarationGlobalImports = (declarationFiles) => {
    const imports = [];
    for (const declarationFile of declarationFiles) {
        let sourceText;
        try {
            sourceText = fs.readFileSync(declarationFile, "utf-8");
        }
        catch {
            continue;
        }
        const sourceFile = ts.createSourceFile(declarationFile, sourceText, ts.ScriptTarget.Latest, false, getScriptKindFromPath(declarationFile));
        const visit = (node) => {
            collectAmbientGlobalImportsFromNode(node, declarationFile, imports);
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
    }
    return imports;
};
//# sourceMappingURL=declaration-module-aliases.js.map