"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryOrchestrator = void 0;
const MemoryProviderRegistry_1 = require("./MemoryProviderRegistry");
const MemoryRetentionPolicy_1 = require("./MemoryRetentionPolicy");
class MemoryOrchestrator {
    registry;
    retention;
    constructor() {
        this.registry = new MemoryProviderRegistry_1.MemoryProviderRegistry();
        this.retention = new MemoryRetentionPolicy_1.MemoryRetentionPolicy();
    }
    async search(input, providers) {
        const selected = this.resolveProviders(providers);
        const all = [];
        for (const provider of selected) {
            try {
                const results = await provider.search(input);
                for (const record of results) {
                    all.push({ provider: provider.name(), record });
                }
            }
            catch (err) {
                // v1.11.0 — never let a single provider's failure halt the search.
                // Honcho/Supermemory swallow internally but other providers may throw.
                console.warn(`[MEMORY-ORCHESTRATOR] provider ${provider.name()} search failed:`, err instanceof Error ? err.message : String(err));
            }
        }
        return this.dedupeAndRank(all, input.query, input.topK || 5);
    }
    async save(input) {
        const record = {
            id: `${input.sourceMissionId || 'mem'}-${Date.now()}`,
            type: input.type,
            namespace: input.namespace || {},
            content: input.content,
            summary: input.summary,
            tags: input.tags || [],
            confidence: input.confidence ?? 0.8,
            sourceMissionId: input.sourceMissionId,
            dedupeKey: input.dedupeKey,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString(),
            keep: input.keep === true ? true : undefined,
        };
        const selected = this.resolveProviders(input.providers);
        for (const provider of selected) {
            try {
                await provider.save({ ...record });
            }
            catch (err) {
                console.warn(`[MEMORY-ORCHESTRATOR] provider ${provider.name()} save failed:`, err instanceof Error ? err.message : String(err));
            }
        }
        return record;
    }
    /**
     * v1.11.0 — Resolve which providers to use.
     *
     * Behavior:
     *   - If caller passes an explicit `providers` array, use that (legacy path).
     *   - Otherwise: pick the primary from OPENLIFE_MEMORY_PROVIDER. If primary
     *     is not 'local', ALSO include 'local' as write-through cache. This
     *     means saveFact always lands in the local file AND in the cloud,
     *     so reads survive a cloud outage and migrations between providers
     *     never lose data.
     */
    resolveProviders(names) {
        let providerNames;
        if (names?.length) {
            providerNames = names;
        }
        else {
            const primary = this.registry.selectPrimary();
            providerNames = primary === 'local' ? ['local'] : [primary, 'local'];
        }
        return providerNames
            .map((name) => this.registry.get(name))
            .filter((provider) => !!provider);
    }
    dedupeAndRank(results, query, topK) {
        const seen = new Set();
        const unique = results.filter((item) => {
            const key = item.record.dedupeKey || `${item.record.summary || item.record.content}`.slice(0, 200);
            if (seen.has(key))
                return false;
            seen.add(key);
            return true;
        });
        return unique
            .filter((item) => this.retention.decide(item.record).keep)
            .sort((a, b) => this.retention.score(b.record, query) - this.retention.score(a.record, query))
            .slice(0, topK);
    }
}
exports.MemoryOrchestrator = MemoryOrchestrator;
