import * as ts from "typescript";
import { getClassNameFromPath, getNamespaceFromPath, } from "../../../resolver.js";
import { getSourceSpan } from "./helpers.js";
import { resolveDynamicImportNamespace } from "../../../resolver/dynamic-import.js";
const hasModuleTypeCollision = (sourceFile, className) => sourceFile.statements.some((statement) => (ts.isClassDeclaration(statement) ||
    ts.isInterfaceDeclaration(statement) ||
    ts.isEnumDeclaration(statement)) &&
    statement.name?.text === className);
const buildModuleContainerClrType = (ownerFilePath, ctx) => {
    const ownerSourceFile = ctx.sourceFilesByPath.get(ownerFilePath);
    const namespace = getNamespaceFromPath(ownerFilePath, ctx.sourceRoot, ctx.rootNamespace);
    const className = getClassNameFromPath(ownerFilePath);
    const containerName = ownerSourceFile && hasModuleTypeCollision(ownerSourceFile, className)
        ? `${className}__Module`
        : className;
    return `${namespace}.${containerName}`;
};
const getDynamicImportEntryType = (entry, ctx) => {
    const declId = ctx.binding.resolveIdentifier(entry.declarationName);
    if (!declId)
        return undefined;
    if (entry.memberKind === "function") {
        const functionDecl = entry.declarationName.parent;
        if (ts.isFunctionDeclaration(functionDecl) ||
            ts.isFunctionExpression(functionDecl) ||
            ts.isMethodDeclaration(functionDecl) ||
            ts.isArrowFunction(functionDecl)) {
            const parameters = functionDecl.parameters.map((param) => ({
                kind: "parameter",
                pattern: {
                    kind: "identifierPattern",
                    name: ts.isIdentifier(param.name) ? param.name.text : "__arg",
                },
                type: param.type
                    ? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(param.type))
                    : undefined,
                initializer: undefined,
                isOptional: !!param.questionToken,
                isRest: !!param.dotDotDotToken,
                passing: "value",
            }));
            const returnType = functionDecl.type
                ? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(functionDecl.type))
                : { kind: "unknownType" };
            return {
                kind: "functionType",
                parameters,
                returnType,
            };
        }
    }
    return ctx.typeSystem.typeOfDecl(declId);
};
export const getDynamicImportPromiseType = (node, ctx) => {
    const resolution = resolveDynamicImportNamespace(node, node.getSourceFile().fileName, {
        checker: ctx.checker,
        compilerOptions: ctx.tsCompilerOptions,
        sourceFilesByPath: ctx.sourceFilesByPath,
    });
    if (!resolution.ok) {
        return undefined;
    }
    const members = resolution.entries.map((entry) => {
        const memberType = getDynamicImportEntryType(entry, ctx) ?? {
            kind: "unknownType",
        };
        return {
            kind: "propertySignature",
            name: entry.exportName,
            type: memberType,
            isOptional: false,
            isReadonly: true,
        };
    });
    return {
        kind: "referenceType",
        name: "Promise",
        typeArguments: [
            members.length === 0
                ? { kind: "referenceType", name: "object" }
                : {
                    kind: "objectType",
                    members,
                },
        ],
    };
};
export const convertDynamicImportNamespaceObject = (node, ctx) => {
    const resolution = resolveDynamicImportNamespace(node, node.getSourceFile().fileName, {
        checker: ctx.checker,
        compilerOptions: ctx.tsCompilerOptions,
        sourceFilesByPath: ctx.sourceFilesByPath,
    });
    const sourceSpan = getSourceSpan(node);
    if (!resolution.ok) {
        return undefined;
    }
    if (resolution.entries.length === 0) {
        return {
            kind: "object",
            properties: [],
            inferredType: { kind: "referenceType", name: "object" },
            contextualType: { kind: "referenceType", name: "object" },
            sourceSpan,
        };
    }
    const properties = [];
    const objectMembers = [];
    for (const entry of resolution.entries) {
        const memberType = getDynamicImportEntryType(entry, ctx);
        if (!memberType) {
            return undefined;
        }
        const containerClrType = buildModuleContainerClrType(entry.ownerFilePath, ctx);
        objectMembers.push({
            kind: "propertySignature",
            name: entry.exportName,
            type: memberType,
            isOptional: false,
            isReadonly: true,
        });
        properties.push({
            kind: "property",
            key: entry.exportName,
            shorthand: false,
            value: {
                kind: "memberAccess",
                object: {
                    kind: "identifier",
                    name: entry.memberName,
                    resolvedClrType: containerClrType,
                    inferredType: { kind: "unknownType" },
                    sourceSpan,
                },
                property: entry.memberName,
                isComputed: false,
                isOptional: false,
                inferredType: memberType,
                sourceSpan,
            },
        });
    }
    const namespaceType = {
        kind: "objectType",
        members: objectMembers,
    };
    return {
        kind: "object",
        properties,
        inferredType: namespaceType,
        contextualType: namespaceType,
        sourceSpan,
    };
};
//# sourceMappingURL=dynamic-import.js.map