import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { logger } from "../../../core/monitoring/logger.js";
import * as zlib from "zlib";
import { promisify } from "util";
const gzip = promisify(zlib.gzip);
const gunzip = promisify(zlib.gunzip);
class PerformanceOptimizer {
  config;
  saveBatch = [];
  batchTimer;
  cache = /* @__PURE__ */ new Map();
  metrics = {
    iterationTime: 0,
    contextLoadTime: 0,
    stateSaveTime: 0,
    memoryUsage: 0,
    tokenCount: 0,
    cacheHitRate: 0
  };
  cacheHits = 0;
  cacheMisses = 0;
  strategies = [];
  constructor(config) {
    this.config = {
      asyncSaves: config?.asyncSaves ?? true,
      batchSize: config?.batchSize || 10,
      compressionLevel: config?.compressionLevel || 2,
      cacheEnabled: config?.cacheEnabled ?? true,
      parallelOperations: config?.parallelOperations ?? true
    };
    this.initializeStrategies();
    this.startMetricsCollection();
  }
  /**
   * Save frame with optimizations
   */
  async saveFrame(frame) {
    const startTime = Date.now();
    if (this.config.asyncSaves) {
      this.addToBatch({
        type: "frame",
        data: frame,
        timestamp: Date.now()
      });
    } else {
      await this.saveFrameInternal(frame);
    }
    this.metrics.stateSaveTime += Date.now() - startTime;
  }
  /**
   * Save iteration with optimizations
   */
  async saveIteration(iteration) {
    const startTime = Date.now();
    const data = this.config.compressionLevel > 0 ? await this.compressData(iteration) : iteration;
    if (this.config.asyncSaves) {
      this.addToBatch({
        type: "iteration",
        data,
        timestamp: Date.now()
      });
    } else {
      await this.saveIterationInternal(data);
    }
    this.metrics.stateSaveTime += Date.now() - startTime;
  }
  /**
   * Load frames with caching
   */
  async loadFrames(query) {
    const startTime = Date.now();
    const cacheKey = this.generateCacheKey("frames", query);
    if (this.config.cacheEnabled) {
      const cached = this.getFromCache(cacheKey);
      if (cached) {
        this.cacheHits++;
        this.metrics.contextLoadTime += Date.now() - startTime;
        return cached;
      }
    }
    this.cacheMisses++;
    const frames = await this.loadFramesInternal(query);
    if (this.config.cacheEnabled) {
      this.setCache(cacheKey, frames, 6e4);
    }
    this.metrics.contextLoadTime += Date.now() - startTime;
    return frames;
  }
  /**
   * Batch save operations
   */
  async flushBatch() {
    if (this.saveBatch.length === 0) return;
    const batch = [...this.saveBatch];
    this.saveBatch = [];
    logger.debug("Flushing batch", { size: batch.length });
    if (this.config.parallelOperations) {
      await Promise.all(batch.map((op) => this.executeSaveOperation(op)));
    } else {
      for (const op of batch) {
        await this.executeSaveOperation(op);
      }
    }
  }
  /**
   * Compress data based on compression level
   */
  async compressData(data) {
    if (this.config.compressionLevel === 0) return data;
    const json = JSON.stringify(data);
    const compressionOptions = {
      level: this.config.compressionLevel * 3
      // Map 1-3 to zlib levels 3-9
    };
    const compressed = await gzip(json, compressionOptions);
    return {
      compressed: true,
      data: compressed.toString("base64"),
      originalSize: json.length,
      compressedSize: compressed.length
    };
  }
  /**
   * Decompress data
   */
  async decompressData(compressed) {
    if (!compressed.compressed) return compressed;
    const buffer = Buffer.from(compressed.data, "base64");
    const decompressed = await gunzip(buffer);
    return JSON.parse(decompressed.toString());
  }
  /**
   * Apply optimization strategies
   */
  async optimize(operation, data) {
    let optimized = data;
    for (const strategy of this.strategies) {
      if (strategy.enabled) {
        try {
          optimized = await strategy.apply(optimized);
        } catch (error) {
          logger.error("Optimization strategy failed", {
            strategy: strategy.name,
            error: error.message
          });
        }
      }
    }
    return optimized;
  }
  /**
   * Get performance metrics
   */
  getMetrics() {
    const totalCacheAttempts = this.cacheHits + this.cacheMisses;
    this.metrics.cacheHitRate = totalCacheAttempts > 0 ? this.cacheHits / totalCacheAttempts : 0;
    this.metrics.memoryUsage = process.memoryUsage().heapUsed;
    return { ...this.metrics };
  }
  /**
   * Clear cache
   */
  clearCache() {
    const size = this.cache.size;
    this.cache.clear();
    logger.debug("Cache cleared", { entries: size });
  }
  /**
   * Enable/disable strategy
   */
  setStrategyEnabled(strategyName, enabled) {
    const strategy = this.strategies.find((s) => s.name === strategyName);
    if (strategy) {
      strategy.enabled = enabled;
      logger.debug("Strategy updated", { name: strategyName, enabled });
    }
  }
  /**
   * Cleanup resources
   */
  cleanup() {
    if (this.batchTimer) {
      clearTimeout(this.batchTimer);
    }
    this.clearCache();
    this.saveBatch = [];
  }
  /**
   * Initialize optimization strategies
   */
  initializeStrategies() {
    this.strategies = [
      {
        name: "deduplication",
        enabled: true,
        priority: 1,
        apply: async (data) => this.deduplicateData(data),
        metrics: () => this.getMetrics()
      },
      {
        name: "chunking",
        enabled: true,
        priority: 2,
        apply: async (data) => this.chunkLargeData(data),
        metrics: () => this.getMetrics()
      },
      {
        name: "lazy-loading",
        enabled: this.config.cacheEnabled,
        priority: 3,
        apply: async (data) => this.createLazyProxy(data),
        metrics: () => this.getMetrics()
      }
    ];
    this.strategies.sort((a, b) => a.priority - b.priority);
  }
  /**
   * Start metrics collection
   */
  startMetricsCollection() {
    setInterval(() => {
      const metrics = this.getMetrics();
      logger.debug("Performance metrics", metrics);
    }, 3e4);
  }
  /**
   * Add operation to batch
   */
  addToBatch(operation) {
    this.saveBatch.push(operation);
    if (!this.batchTimer) {
      this.batchTimer = setTimeout(() => {
        this.flushBatch().catch((error) => {
          logger.error("Batch flush failed", { error: error.message });
        });
        this.batchTimer = void 0;
      }, 1e3);
    }
    if (this.saveBatch.length >= this.config.batchSize) {
      if (this.batchTimer) {
        clearTimeout(this.batchTimer);
        this.batchTimer = void 0;
      }
      this.flushBatch().catch((error) => {
        logger.error("Batch flush failed", { error: error.message });
      });
    }
  }
  /**
   * Execute save operation
   */
  async executeSaveOperation(operation) {
    switch (operation.type) {
      case "frame":
        await this.saveFrameInternal(operation.data);
        break;
      case "iteration":
        await this.saveIterationInternal(operation.data);
        break;
      default:
        logger.warn("Unknown operation type", { type: operation.type });
    }
  }
  /**
   * Internal frame save
   */
  async saveFrameInternal(frame) {
    logger.debug("Frame saved", { frameId: frame.frame_id });
  }
  /**
   * Internal iteration save
   */
  async saveIterationInternal(iteration) {
    logger.debug("Iteration saved", { iteration: iteration.number });
  }
  /**
   * Internal frame load
   */
  async loadFramesInternal(query) {
    return [];
  }
  /**
   * Generate cache key
   */
  generateCacheKey(type, params) {
    return `${type}:${JSON.stringify(params)}`;
  }
  /**
   * Get from cache
   */
  getFromCache(key) {
    const entry = this.cache.get(key);
    if (!entry) return void 0;
    if (entry.expiry && entry.expiry < Date.now()) {
      this.cache.delete(key);
      return void 0;
    }
    return entry.data;
  }
  /**
   * Set cache entry
   */
  setCache(key, data, ttl) {
    const entry = {
      data,
      timestamp: Date.now(),
      expiry: ttl ? Date.now() + ttl : void 0
    };
    this.cache.set(key, entry);
    if (this.cache.size > 100) {
      const entries = Array.from(this.cache.entries());
      entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
      for (let i = 0; i < 20; i++) {
        this.cache.delete(entries[i][0]);
      }
    }
  }
  /**
   * Deduplicate data
   */
  deduplicateData(data) {
    if (Array.isArray(data)) {
      const seen = /* @__PURE__ */ new Set();
      return data.filter((item) => {
        const key = JSON.stringify(item);
        if (seen.has(key)) {
          return false;
        }
        seen.add(key);
        return true;
      });
    }
    return data;
  }
  /**
   * Chunk large data
   */
  chunkLargeData(data) {
    const json = JSON.stringify(data);
    if (json.length > 1e5) {
      logger.debug("Large data detected", { size: json.length });
    }
    return data;
  }
  /**
   * Create lazy-loading proxy
   */
  createLazyProxy(data) {
    return data;
  }
}
export {
  PerformanceOptimizer
};
//# sourceMappingURL=performance-optimizer.js.map
