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 "../monitoring/logger.js";
import { getQueryStatistics } from "../trace/db-trace-wrapper.js";
function getEnv(key, defaultValue) {
  const value = process.env[key];
  if (value === void 0) {
    if (defaultValue !== void 0) return defaultValue;
    throw new Error(`Environment variable ${key} is required`);
  }
  return value;
}
function getOptionalEnv(key) {
  return process.env[key];
}
class PerformanceProfiler {
  metrics = /* @__PURE__ */ new Map();
  hotPaths = /* @__PURE__ */ new Map();
  samples = /* @__PURE__ */ new Map();
  isEnabled = true;
  sampleLimit = 1e3;
  hotPathThreshold = 5;
  // Operations taking > 5ms are considered hot
  constructor(options = {}) {
    this.isEnabled = options.enabled ?? true;
    this.sampleLimit = options.sampleLimit ?? 1e3;
    this.hotPathThreshold = options.hotPathThreshold ?? 5;
  }
  /**
   * Start timing an operation
   */
  startTiming(operationName) {
    if (!this.isEnabled) {
      return () => {
      };
    }
    const startTime = performance.now();
    return (metadata) => {
      this.endTiming(operationName, startTime, metadata);
    };
  }
  /**
   * Time a function execution
   */
  async timeFunction(operationName, fn, metadata) {
    if (!this.isEnabled) {
      return await fn();
    }
    const endTimer = this.startTiming(operationName);
    try {
      const result = await fn();
      endTimer(metadata);
      return result;
    } catch (error) {
      endTimer({ ...metadata, error: true });
      throw error;
    }
  }
  /**
   * Record timing manually
   */
  recordTiming(operationName, durationMs, metadata) {
    if (!this.isEnabled) return;
    this.endTiming(operationName, performance.now() - durationMs, metadata);
  }
  /**
   * Get performance metrics for an operation
   */
  getMetrics(operationName) {
    return this.metrics.get(operationName);
  }
  /**
   * Get all performance metrics
   */
  getAllMetrics() {
    return new Map(this.metrics);
  }
  /**
   * Get hot paths sorted by impact
   */
  getHotPaths(limit = 10) {
    return Array.from(this.hotPaths.values()).sort((a, b) => b.frequency * b.avgDuration - a.frequency * a.avgDuration).slice(0, limit);
  }
  /**
   * Generate comprehensive performance report
   */
  generateReport(db) {
    const hotPaths = this.getHotPaths(20);
    const recommendations = this.generateRecommendations(hotPaths);
    const report = {
      timestamp: Date.now(),
      hotPaths,
      databaseMetrics: db ? getQueryStatistics(db) : null,
      memoryUsage: process.memoryUsage(),
      cacheMetrics: null,
      // Will be filled by query cache if available
      recommendations
    };
    logger.info("Performance report generated", {
      hotPathsCount: hotPaths.length,
      recommendationsCount: recommendations.length,
      topHotPath: hotPaths[0]?.path
    });
    return report;
  }
  /**
   * Reset all metrics
   */
  reset() {
    this.metrics.clear();
    this.hotPaths.clear();
    this.samples.clear();
    logger.info("Performance metrics reset");
  }
  /**
   * Export metrics to JSON
   */
  exportMetrics() {
    const data = {
      timestamp: Date.now(),
      metrics: Object.fromEntries(this.metrics),
      hotPaths: Object.fromEntries(this.hotPaths),
      config: {
        sampleLimit: this.sampleLimit,
        hotPathThreshold: this.hotPathThreshold,
        enabled: this.isEnabled
      }
    };
    return JSON.stringify(data, null, 2);
  }
  /**
   * Enable/disable profiling
   */
  setEnabled(enabled) {
    this.isEnabled = enabled;
    logger.info(`Performance profiling ${enabled ? "enabled" : "disabled"}`);
  }
  /**
   * End timing for an operation
   */
  endTiming(operationName, startTime, metadata) {
    const duration = performance.now() - startTime;
    const timestamp = Date.now();
    this.updateMetrics(operationName, duration, timestamp);
    if (duration > this.hotPathThreshold) {
      this.trackHotPath(operationName, duration, timestamp, metadata);
    }
    this.storeSample(operationName, duration, timestamp, metadata);
  }
  /**
   * Update performance metrics for an operation
   */
  updateMetrics(operationName, duration, timestamp) {
    const existing = this.metrics.get(operationName);
    if (!existing) {
      this.metrics.set(operationName, {
        operationName,
        callCount: 1,
        totalTimeMs: duration,
        avgTimeMs: duration,
        minTimeMs: duration,
        maxTimeMs: duration,
        p95TimeMs: duration,
        lastExecuted: timestamp
      });
    } else {
      existing.callCount++;
      existing.totalTimeMs += duration;
      existing.avgTimeMs = existing.totalTimeMs / existing.callCount;
      existing.minTimeMs = Math.min(existing.minTimeMs, duration);
      existing.maxTimeMs = Math.max(existing.maxTimeMs, duration);
      existing.lastExecuted = timestamp;
      existing.p95TimeMs = this.calculateP95(operationName);
    }
  }
  /**
   * Track hot path
   */
  trackHotPath(operationName, duration, timestamp, metadata) {
    const existing = this.hotPaths.get(operationName);
    if (!existing) {
      this.hotPaths.set(operationName, {
        path: operationName,
        frequency: 1,
        avgDuration: duration,
        totalDuration: duration,
        lastSeen: timestamp,
        samples: [{ timestamp, duration, metadata }]
      });
    } else {
      existing.frequency++;
      existing.totalDuration += duration;
      existing.avgDuration = existing.totalDuration / existing.frequency;
      existing.lastSeen = timestamp;
      existing.samples.push({ timestamp, duration, metadata });
      if (existing.samples.length > 100) {
        existing.samples = existing.samples.slice(-100);
      }
    }
  }
  /**
   * Store performance sample
   */
  storeSample(operationName, duration, timestamp, metadata) {
    if (!this.samples.has(operationName)) {
      this.samples.set(operationName, []);
    }
    const samples = this.samples.get(operationName);
    samples.push({ timestamp, duration, metadata });
    if (samples.length > this.sampleLimit) {
      samples.splice(0, samples.length - this.sampleLimit);
    }
  }
  /**
   * Calculate 95th percentile from samples
   */
  calculateP95(operationName) {
    const samples = this.samples.get(operationName);
    if (!samples || samples.length === 0) return 0;
    const durations = samples.map((s) => s.duration).sort((a, b) => a - b);
    const index = Math.floor(durations.length * 0.95);
    return durations[index] || 0;
  }
  /**
   * Generate optimization recommendations
   */
  generateRecommendations(hotPaths) {
    const recommendations = [];
    for (const hotPath of hotPaths.slice(0, 5)) {
      const impact = hotPath.frequency * hotPath.avgDuration;
      if (hotPath.path.includes("getFrameContext") && hotPath.avgDuration > 10) {
        recommendations.push(
          `Consider caching frame context for ${hotPath.path} (avg: ${hotPath.avgDuration.toFixed(1)}ms)`
        );
      }
      if (hotPath.path.includes("getFrameEvents") && hotPath.frequency > 100) {
        recommendations.push(
          `High frequency event queries detected in ${hotPath.path} (${hotPath.frequency} calls). Consider pagination or caching.`
        );
      }
      if (hotPath.path.includes("bulkInsert") && hotPath.avgDuration > 50) {
        recommendations.push(
          `Slow bulk insertion in ${hotPath.path}. Consider increasing batch size or using prepared statements.`
        );
      }
      if (impact > 1e3) {
        recommendations.push(
          `High impact operation: ${hotPath.path} (${impact.toFixed(0)}ms total impact). Consider optimization.`
        );
      }
    }
    const memUsage = process.memoryUsage();
    if (memUsage.heapUsed / memUsage.heapTotal > 0.8) {
      recommendations.push(
        "High memory usage detected. Consider implementing cleanup routines or reducing cache sizes."
      );
    }
    if (recommendations.length === 0) {
      recommendations.push("No significant performance issues detected.");
    }
    return recommendations;
  }
}
let globalProfiler = null;
function getProfiler() {
  if (!globalProfiler) {
    globalProfiler = new PerformanceProfiler({
      enabled: process.env["NODE_ENV"] !== "production" || process.env["STACKMEMORY_PROFILING"] === "true"
    });
  }
  return globalProfiler;
}
async function timeOperation(operationName, fn, metadata) {
  return getProfiler().timeFunction(operationName, fn, metadata);
}
function performanceMonitor(operationName) {
  return function(target, propertyKey, descriptor) {
    const originalMethod = descriptor.value;
    const finalOperationName = operationName || `${target.constructor.name}.${propertyKey}`;
    descriptor.value = async function(...args) {
      return getProfiler().timeFunction(
        finalOperationName,
        () => originalMethod.apply(this, args)
      );
    };
    return descriptor;
  };
}
class StackMemoryPerformanceMonitor {
  profiler = getProfiler();
  /**
   * Monitor frame operations
   */
  monitorFrameOperations(frameManager) {
    this.wrapMethod(frameManager, "getFrame", "FrameManager.getFrame");
    this.wrapMethod(
      frameManager,
      "getFrameEvents",
      "FrameManager.getFrameEvents"
    );
    this.wrapMethod(
      frameManager,
      "getFrameAnchors",
      "FrameManager.getFrameAnchors"
    );
    this.wrapMethod(
      frameManager,
      "getHotStackContext",
      "FrameManager.getHotStackContext"
    );
  }
  /**
   * Monitor database operations
   */
  monitorDatabaseOperations(db) {
    const originalPrepare = db.prepare;
    db.prepare = function(sql) {
      const stmt = originalPrepare.call(this, sql);
      return wrapStatement(stmt, sql);
    };
  }
  /**
   * Wrap a method with performance monitoring
   */
  wrapMethod(obj, methodName, operationName) {
    const original = obj[methodName];
    if (typeof original !== "function") return;
    obj[methodName] = async function(...args) {
      return getProfiler().timeFunction(
        operationName,
        () => original.apply(this, args)
      );
    };
  }
}
function wrapStatement(stmt, sql) {
  const operationName = `SQL.${sql.trim().split(" ")[0].toUpperCase()}`;
  const originalRun = stmt.run;
  const originalGet = stmt.get;
  const originalAll = stmt.all;
  stmt.run = function(...args) {
    return getProfiler().timeFunction(
      `${operationName}.run`,
      () => originalRun.apply(this, args)
    );
  };
  stmt.get = function(...args) {
    return getProfiler().timeFunction(
      `${operationName}.get`,
      () => originalGet.apply(this, args)
    );
  };
  stmt.all = function(...args) {
    return getProfiler().timeFunction(
      `${operationName}.all`,
      () => originalAll.apply(this, args)
    );
  };
  return stmt;
}
export {
  PerformanceProfiler,
  StackMemoryPerformanceMonitor,
  getProfiler,
  performanceMonitor,
  timeOperation
};
//# sourceMappingURL=performance-profiler.js.map
