import * as nodeFsSync from "node:fs";
import { createSecretStore, MigratingSecretStore } from "auth-store";
import { createCliEnvironment } from "./environment.js";
import { createServiceRegistry } from "./service-registry.js";
import { createCommandContextFactory } from "./context.js";
import { createPromptLibrary } from "./prompts.js";
import { checkAuth } from "poe-oauth";
import { createOptionResolvers } from "./options.js";
import { createLoggerFactory } from "./logger.js";
import { ErrorLogger } from "./error-logger.js";
import { runCommand } from "@poe-code/agent-spawn";
import { text, symbols, confirm as dsConfirm, isCancel, cancel as dsCancel } from "toolcraft-design";
import { getDefaultProviders } from "../providers/index.js";
import { allAuthProviders, ProviderRegistry, poeProvider } from "@poe-code/providers";
import { createPoeCodeCommandRunner } from "./poe-code-command-runner.js";
import { OperationCancelledError } from "./errors.js";
import { resolveApiKeyViaOAuth } from "./oauth-login.js";
import { providerCredentialFileName, usesLegacyPoeCredentialMirror } from "./provider-auth-storage.js";
export function createCliContainer(dependencies) {
    const environment = createCliEnvironment({
        cwd: dependencies.env.cwd,
        homeDir: dependencies.env.homeDir,
        platform: dependencies.env.platform,
        variables: dependencies.env.variables
    });
    const loggerFactory = createLoggerFactory(dependencies.logger, {
        intro: text.intro,
        resolvedSymbol: symbols.resolved
    });
    // Create error logger - use node:fs for sync operations
    const errorLogger = new ErrorLogger({
        fs: nodeFsSync,
        logDir: environment.logDir,
        logToStderr: true
    });
    // Attach error logger to logger factory.
    // When a custom logger emitter is provided (e.g. tests), skip wiring the
    // ErrorLogger — the emitter already captures error messages via emit().
    if (!dependencies.logger) {
        loggerFactory.setErrorLogger(errorLogger);
    }
    const contextFactory = createCommandContextFactory({
        fs: dependencies.fs
    });
    const httpClient = dependencies.httpClient ??
        (async (url, init) => {
            const response = await globalThis.fetch(url, init);
            return {
                ok: response.ok,
                status: response.status,
                json: () => response.json(),
                text: () => response.text()
            };
        });
    const commandRunner = dependencies.commandRunner ?? runCommand;
    const promptLibrary = createPromptLibrary();
    const authProviders = allAuthProviders;
    const requireAuthProvider = (providerId) => {
        const provider = authProviders.find((candidate) => candidate.id === providerId);
        if (!provider) {
            throw new Error(`Unknown provider: "${providerId}".`);
        }
        return provider;
    };
    const authFs = {
        readFile: (filePath, encoding) => dependencies.fs.readFile(filePath, encoding),
        writeFile: (filePath, data, opts) => dependencies.fs.writeFile(filePath, data, opts),
        mkdir: (directoryPath, opts) => dependencies.fs.mkdir(directoryPath, opts).then(() => undefined),
        lstat: (filePath) => dependencies.fs.lstat(filePath),
        rename: (oldPath, newPath) => dependencies.fs.rename(oldPath, newPath),
        unlink: (filePath) => dependencies.fs.unlink(filePath),
        chmod: (filePath, mode) => dependencies.fs.chmod ? dependencies.fs.chmod(filePath, mode) : Promise.resolve()
    };
    const createAuthStore = (defaultFileName) => createSecretStore({
        backendEnvVar: "POE_AUTH_BACKEND",
        env: dependencies.env.variables,
        platform: dependencies.env.platform,
        fileStore: {
            fs: authFs,
            salt: "poe-code:encrypted-file-auth-store:v1",
            defaultDirectory: ".poe-code",
            defaultFileName,
            getHomeDirectory: () => dependencies.env.homeDir
        }
    }).store;
    const legacyAuthStore = createAuthStore("credentials.enc");
    const providerAuthStores = new Map();
    const getProviderAuthStore = (provider) => {
        const credentialFileName = providerCredentialFileName(provider);
        const cached = providerAuthStores.get(credentialFileName);
        if (cached) {
            return cached;
        }
        const store = createAuthStore(credentialFileName);
        const providerStore = usesLegacyPoeCredentialMirror(provider) ? new MigratingSecretStore(store, legacyAuthStore) : store;
        providerAuthStores.set(credentialFileName, providerStore);
        return providerStore;
    };
    const poeAuthStore = getProviderAuthStore(poeProvider);
    const readApiKey = poeAuthStore.get.bind(poeAuthStore);
    const writeApiKey = poeAuthStore.set.bind(poeAuthStore);
    const deleteApiKey = poeAuthStore.delete.bind(poeAuthStore);
    const createPreviewProviderStore = (providerId, fs) => {
        const provider = requireAuthProvider(providerId);
        const createPreviewStore = (defaultFileName) => createSecretStore({
            backendEnvVar: "POE_AUTH_BACKEND",
            env: dependencies.env.variables,
            platform: dependencies.env.platform,
            fileStore: {
                fs: {
                    readFile: (filePath, encoding) => fs.readFile(filePath, encoding),
                    writeFile: (filePath, data, opts) => fs.writeFile(filePath, data, opts),
                    mkdir: (directoryPath, opts) => fs.mkdir(directoryPath, opts).then(() => undefined),
                    lstat: (filePath) => fs.lstat(filePath),
                    rename: (oldPath, newPath) => fs.rename(oldPath, newPath),
                    unlink: (filePath) => fs.unlink(filePath),
                    chmod: (filePath, mode) => fs.chmod ? fs.chmod(filePath, mode) : Promise.resolve()
                },
                salt: "poe-code:encrypted-file-auth-store:v1",
                defaultDirectory: ".poe-code",
                defaultFileName,
                getHomeDirectory: () => dependencies.env.homeDir
            }
        });
        const store = createPreviewStore(providerCredentialFileName(provider));
        if (store.backend !== "file") {
            return undefined;
        }
        return usesLegacyPoeCredentialMirror(provider)
            ? new MigratingSecretStore(store.store, createPreviewStore("credentials.enc").store)
            : store.store;
    };
    const oauthEnabled = (dependencies.env.variables ?? process.env).POE_CODE_OAUTH_LOGIN !== "0";
    const options = createOptionResolvers({
        prompts: dependencies.prompts,
        promptLibrary,
        apiKeyStore: {
            read: readApiKey,
            write: writeApiKey
        },
        checkAuth: async (apiKey) => (await checkAuth({ apiKey, baseUrl: environment.poeBaseUrl })) !== null,
        confirm: async (message) => {
            const result = await dsConfirm({ message });
            if (isCancel(result)) {
                dsCancel("Operation cancelled.");
                throw new OperationCancelledError();
            }
            return result === true;
        },
        loginViaOAuth: oauthEnabled
            ? () => resolveApiKeyViaOAuth({ tokenEndpoint: `${environment.poeBaseUrl}/token` })
            : undefined
    });
    const registry = createServiceRegistry();
    const providerRegistry = new ProviderRegistry(authProviders, getProviderAuthStore, {
        envVars: environment.variables
    });
    const providers = getDefaultProviders().filter((adapter) => !adapter.disabled);
    for (const adapter of providers) {
        registry.register(adapter);
    }
    let container = null;
    const wrappedRunner = createPoeCodeCommandRunner({
        getContainer: () => container,
        baseRunner: commandRunner
    });
    container = {
        env: environment,
        fs: dependencies.fs,
        prompts: dependencies.prompts,
        promptLibrary,
        loggerFactory,
        errorLogger,
        options,
        contextFactory,
        registry,
        providerRegistry,
        httpClient,
        commandRunner: wrappedRunner,
        providers,
        dependencies,
        readApiKey,
        writeApiKey,
        deleteApiKey,
        createPreviewProviderStore
    };
    return container;
}
//# sourceMappingURL=container.js.map