import * as path from "node:path";
import { resolvePath } from "../../utils/paths.js";
import { createEventBus } from "../event-bus.js";
import { createSyntheticSourceInfo } from "../source-info.js";
import { endTimingSpan, startTimingSpan } from "../timings.js";
import { yieldToEventLoop } from "../../utils/event-loop.js";
import { createExtensionAPI } from "./loader-api.js";
import { emptyWorkflowResourceProvider, } from "./loader-resources.js";
import { createExtensionRuntime } from "./loader-runtime.js";
import { loadExtensionModule, useExtensionCacheCwd, } from "./loader-virtual-modules.js";
/**
 * Create an Extension object with empty collections.
 */
function createExtension(extensionPath, resolvedPath) {
    const source = extensionPath.startsWith("<") && extensionPath.endsWith(">")
        ? extensionPath.slice(1, -1).split(":")[0] || "temporary"
        : "local";
    const baseDir = extensionPath.startsWith("<") ? undefined : path.dirname(resolvedPath);
    return {
        path: extensionPath,
        resolvedPath,
        sourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),
        handlers: new Map(),
        tools: new Map(),
        messageRenderers: new Map(),
        commands: new Map(),
        flags: new Map(),
        shortcuts: new Map(),
    };
}
async function loadExtension(extensionPath, cwd, eventBus, runtime, workflowResourceProvider = emptyWorkflowResourceProvider, resourceLoaderInheritanceSnapshotProvider, cacheToken) {
    const resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });
    try {
        const moduleSpan = startTimingSpan(`loadExtensions.${extensionPath}.module`, "extensions");
        const factory = await loadExtensionModule(resolvedPath, cacheToken);
        endTimingSpan(moduleSpan);
        if (!factory) {
            return {
                extension: null,
                error: `Extension does not export a valid factory function: ${extensionPath}`,
            };
        }
        const extension = createExtension(extensionPath, resolvedPath);
        const api = createExtensionAPI(extension, runtime, cwd, eventBus, workflowResourceProvider, resourceLoaderInheritanceSnapshotProvider);
        const factorySpan = startTimingSpan(`loadExtensions.${extensionPath}.factory`, "extensions");
        await factory(api);
        endTimingSpan(factorySpan);
        return { extension, error: null };
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return { extension: null, error: `Failed to load extension: ${message}` };
    }
}
/**
 * Create an Extension from an inline factory function.
 */
export async function loadExtensionFromFactory(factory, cwd, eventBus, runtime, extensionPath = "<inline>", workflowResourceProvider = emptyWorkflowResourceProvider, resourceLoaderInheritanceSnapshotProvider) {
    const extension = createExtension(extensionPath, extensionPath);
    const resolvedCwd = resolvePath(cwd);
    const api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus, workflowResourceProvider, resourceLoaderInheritanceSnapshotProvider);
    await factory(api);
    return extension;
}
/**
 * Load extensions from paths.
 */
async function loadExtensionsInternal(paths, cwd, eventBus, workflowResourceProvider = emptyWorkflowResourceProvider, runtime, resourceLoaderInheritanceSnapshotProvider, useCache = false) {
    const extensions = [];
    const errors = [];
    const cacheToken = useCache ? useExtensionCacheCwd(cwd) : undefined;
    const resolvedCwd = cacheToken?.cwd ?? resolvePath(cwd);
    const resolvedEventBus = eventBus ?? createEventBus();
    const resolvedRuntime = runtime ?? createExtensionRuntime();
    let processedExtensionCount = 0;
    for (const extPath of paths) {
        if (processedExtensionCount > 0) {
            await yieldToEventLoop();
        }
        const extensionSpan = startTimingSpan(`loadExtensions.${extPath}.total`, "extensions");
        const { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, resolvedRuntime, workflowResourceProvider, resourceLoaderInheritanceSnapshotProvider, cacheToken);
        endTimingSpan(extensionSpan);
        processedExtensionCount += 1;
        if (error) {
            errors.push({ path: extPath, error });
            continue;
        }
        if (extension) {
            extensions.push(extension);
        }
    }
    return {
        extensions,
        errors,
        runtime: resolvedRuntime,
    };
}
export async function loadExtensions(paths, cwd, eventBus, workflowResourceProvider = emptyWorkflowResourceProvider, runtime, resourceLoaderInheritanceSnapshotProvider) {
    return loadExtensionsInternal(paths, cwd, eventBus, workflowResourceProvider, runtime, resourceLoaderInheritanceSnapshotProvider);
}
export async function loadExtensionsCached(paths, cwd, eventBus, workflowResourceProvider = emptyWorkflowResourceProvider, runtime, resourceLoaderInheritanceSnapshotProvider) {
    return loadExtensionsInternal(paths, cwd, eventBus, workflowResourceProvider, runtime, resourceLoaderInheritanceSnapshotProvider, true);
}
//# sourceMappingURL=loader-core.js.map