/**
 * Multi-Agent Cache Manager
 *
 * Implements shared KV cache with Byzantine consensus.
 */
export class CacheManager {
    sharedCache = new Map();
    agentDeltas = new Map();
    version = 0;
    locks = new Map();
    syncInterval = 50; // tokens
    compressionThreshold = 0.1;
    /**
     * Initialize shared cache for a layer
     */
    initLayer(layerIndex, kvCache) {
        // Compress using SLERP-like merge
        const compressed = this.compress(kvCache);
        this.sharedCache.set(layerIndex, compressed);
    }
    /**
     * Compress KV cache using SLERP-inspired merge
     */
    compress(kvCache) {
        if (kvCache.length < 2) {
            return {
                direction: kvCache[0] || [],
                magnitudes: [1],
                retained: new Map(),
                indices: kvCache.map((_, i) => i)
            };
        }
        // Start from middle
        const mid = Math.floor(kvCache.length / 2);
        // Merge middle with previous (like SLERP)
        const merged = this.slerpMerge(kvCache[mid], kvCache[mid - 1], 0.5);
        // Compute magnitudes
        const magnitudes = kvCache.map(v => this.magnitude(v));
        // Retain highly distinct tokens (simple threshold)
        const retained = new Map();
        const threshold = 0.3;
        for (let i = mid; i < kvCache.length; i++) {
            const sim = this.cosineSimilarity(kvCache[i], merged);
            if (sim < threshold) {
                retained.set(i, kvCache[i]);
            }
        }
        return {
            direction: this.normalize(merged),
            magnitudes: magnitudes.slice(mid),
            retained,
            indices: kvCache.map((_, i) => i).slice(mid)
        };
    }
    /**
     * SLERP-inspired merge
     */
    slerpMerge(v1, v2, t) {
        // Simplified SLERP
        const dot = this.dotProduct(v1, v2) / (this.magnitude(v1) * this.magnitude(v2) || 1);
        const omega = Math.acos(Math.max(-1, Math.min(1, dot)));
        const sinOmega = Math.sin(omega);
        if (sinOmega < 1e-6) {
            return v1.map((x, i) => (1 - t) * x + t * (v2[i] || 0));
        }
        const a = Math.sin((1 - t) * omega) / sinOmega;
        const b = Math.sin(t * omega) / sinOmega;
        return v1.map((x, i) => a * x + b * (v2[i] || 0));
    }
    /**
     * Acquire read lock (non-blocking)
     */
    acquireReadLock(layerIndex) {
        const current = this.locks.get(layerIndex) || 'none';
        if (current === 'write') {
            return false; // Blocked
        }
        this.locks.set(layerIndex, 'read');
        return true;
    }
    /**
     * Acquire write lock
     */
    acquireWriteLock(layerIndex) {
        const current = this.locks.get(layerIndex) || 'none';
        if (current !== 'none') {
            return false; // Blocked
        }
        this.locks.set(layerIndex, 'write');
        return true;
    }
    /**
     * Release lock
     */
    releaseLock(layerIndex) {
        this.locks.set(layerIndex, 'none');
    }
    /**
     * Get cache entry for agent
     */
    getForAgent(agentId, layerIndex) {
        const entry = this.sharedCache.get(layerIndex);
        if (!entry)
            return [];
        // Get agent's delta
        const agentDeltaMap = this.agentDeltas.get(agentId) || new Map();
        const delta = agentDeltaMap.get(layerIndex) || [];
        // Restore: direction * magnitude + delta
        const restored = entry.direction.map((d, i) => d * (entry.magnitudes[i] || 1) + (delta[i] || 0));
        // Add retained tokens
        for (const [idx, token] of entry.retained) {
            if (idx < restored.length) {
                restored[idx] += this.magnitude(token);
            }
        }
        return restored;
    }
    /**
     * Update agent delta
     */
    updateDelta(agentId, layerIndex, delta) {
        if (!this.agentDeltas.has(agentId)) {
            this.agentDeltas.set(agentId, new Map());
        }
        const agentDeltaMap = this.agentDeltas.get(agentId);
        const existing = agentDeltaMap.get(layerIndex) || [];
        // Accumulate delta
        const newDelta = delta.map((d, i) => d + (existing[i] || 0));
        agentDeltaMap.set(layerIndex, newDelta);
    }
    /**
     * Sync agent delta to shared cache
     */
    syncToShared(agentId, layerIndex) {
        const agentDeltaMap = this.agentDeltas.get(agentId);
        if (!agentDeltaMap)
            return;
        const delta = agentDeltaMap.get(layerIndex);
        if (!delta)
            return;
        // Check if delta is significant
        const entry = this.sharedCache.get(layerIndex);
        if (!entry)
            return;
        const mag = this.magnitude(entry.direction);
        const deltaMag = this.magnitude(delta);
        if (deltaMag > this.compressionThreshold * mag) {
            // Merge delta into shared
            const merged = entry.direction.map((d, i) => d + delta[i] * 0.1);
            this.sharedCache.set(layerIndex, {
                ...entry,
                direction: this.normalize(merged),
                magnitudes: entry.magnitudes.map(m => m + deltaMag * 0.1)
            });
            // Reset agent delta
            agentDeltaMap.set(layerIndex, []);
            this.version++;
        }
    }
    /**
     * Get cache statistics
     */
    getStats() {
        let totalOriginal = 0;
        let totalCompressed = 0;
        for (const entry of this.sharedCache.values()) {
            totalOriginal += entry.magnitudes.length * entry.direction.length;
            totalCompressed += entry.direction.length + entry.magnitudes.length;
            totalCompressed += Array.from(entry.retained.values())
                .reduce((sum, v) => sum + v.length, 0);
        }
        return {
            layers: this.sharedCache.size,
            agents: this.agentDeltas.size,
            version: this.version,
            compressionRatio: totalOriginal / (totalCompressed || 1)
        };
    }
    // ===== Utilities =====
    magnitude(v) {
        return Math.sqrt(v.reduce((sum, x) => sum + x * x, 0));
    }
    normalize(v) {
        const mag = this.magnitude(v);
        if (mag === 0)
            return v;
        return v.map(x => x / mag);
    }
    dotProduct(a, b) {
        return a.reduce((sum, x, i) => sum + x * (b[i] || 0), 0);
    }
    cosineSimilarity(a, b) {
        const dot = this.dotProduct(a, b);
        const magA = this.magnitude(a);
        const magB = this.magnitude(b);
        return dot / (magA * magB || 1);
    }
}
export const createCacheManager = () => new CacheManager();
