/**
 * ContextManagerV2 manages V2 context lifecycle, caching, and persistence.
 *
 * Responsibilities:
 * - Load/save context state from/to storage
 * - Cache active contexts in memory
 * - Create ephemeral contexts for one-off operations
 * - Migrate older context versions to current version
 */
import { getPrefixedLogger } from "../../../util/logger.js";
import { ContextV2 } from "./context.js";
import { migrateContext } from "./migrations/index.js";
const logger = getPrefixedLogger("[context-manager-v2]");
/**
 * Manager for creating and managing V2 conversation contexts.
 */
export class ContextManagerV2 {
    storage;
    contexts = new Map();
    rootDir;
    getModeState;
    constructor(options) {
        this.storage = options.storage;
        this.rootDir = options.rootDir;
        this.getModeState = options.getModeState;
    }
    getContextKey(id) {
        return `${id.appId}::${id.userId}::${id.name}`;
    }
    async getOrCreateContext(id, summarizationModel, config, tracer) {
        const key = id ? this.getContextKey(id) : undefined;
        if (key) {
            const cached = this.contexts.get(key);
            if (cached) {
                if (config) {
                    cached.updateConfig(config);
                }
                return cached;
            }
        }
        const onPersist = id
            ? async (record) => {
                await this.saveContext(id, record);
            }
            : undefined;
        const record = id ? await this.loadContext(id) : undefined;
        const options = {
            summarizationModel,
            config,
            onPersist,
            tracer,
            rootDir: this.rootDir,
            getModeState: this.getModeState,
        };
        let context;
        if (record) {
            logger.info(`Restored context '${id?.name}' from storage`);
            context = ContextV2.fromRecord(record, options);
        }
        else {
            logger.info(`Creating new context '${id?.name ?? "ephemeral"}'`);
            context = new ContextV2(options);
        }
        if (key) {
            this.contexts.set(key, context);
        }
        return context;
    }
    /**
     * Gets an already-loaded context without async operations.
     * For use by tools executing within an LLM stream where context is already loaded.
     */
    getLoadedContext(id) {
        const key = this.getContextKey(id);
        return this.contexts.get(key);
    }
    /**
     * Clears a specific context from the in-memory cache only.
     */
    clearContext(id) {
        const key = this.getContextKey(id);
        const context = this.contexts.get(key);
        context?.dispose();
        this.contexts.delete(key);
    }
    /**
     * Clears all contexts from cache and storage.
     */
    async clearAllContexts() {
        for (const context of this.contexts.values()) {
            context.dispose();
        }
        this.contexts.clear();
        await this.storage.deleteAllContexts();
    }
    /**
     * Loads context from persistent storage.
     * Handles version migration automatically.
     */
    async loadContext(id) {
        try {
            const rawRecord = await this.storage.loadContext(id);
            if (rawRecord === null) {
                return null;
            }
            const result = migrateContext(rawRecord, 2);
            if (!result.success) {
                logger.warn(`Context '${id.name}' migration failed: ${result.reason}. ` +
                    `Context will be deleted and a fresh conversation will start.`);
                try {
                    await this.storage.deleteContext(id);
                }
                catch (deleteErr) {
                    logger.error(`Failed to delete context '${id.name}' after migration failure: ${deleteErr}`);
                }
                return null;
            }
            return result.record;
        }
        catch (err) {
            logger.error(`Failed to load context for '${id.name}': ${err}`);
            return null;
        }
    }
    /**
     * Saves context to persistent storage.
     */
    async saveContext(id, record) {
        try {
            await this.storage.saveContext(id, record);
        }
        catch (err) {
            logger.error(`Failed to save context for '${id.name}': ${err}`);
        }
    }
}
//# sourceMappingURL=manager.js.map