import { Injectable } from '@nestjs/common';
import { PerformanceObserver, performance } from 'perf_hooks';
import { CacheService } from './cache.service';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class PerformanceService {
  private performanceObserver: PerformanceObserver;
  private cacheTTL = 3600; // 1 hour

  constructor(
    private cacheService: CacheService,
    private configService: ConfigService,
  ) {
    this.performanceObserver = new PerformanceObserver((list) => {
      const entries = list.getEntries();
      entries.forEach((entry) => {
        this.logPerformance(entry);
      });
    });

    this.performanceObserver.observe({
      entryTypes: ['measure'],
      buffered: true,
    });
  }

  private async logPerformance(entry: PerformanceEntry) {
    const { name, duration, startTime } = entry;
    const timestamp = new Date(startTime).toISOString();

    // Store performance metrics in cache
    await this.cacheService.set(
      `performance:${name}:${timestamp}`,
      {
        name,
        duration,
        timestamp,
        environment: this.configService.get('NODE_ENV'),
      },
      this.cacheTTL,
    );

    // Log to console for debugging
    console.log(`Performance: ${name} took ${duration}ms`);
  }

  measure<T>(name: string, fn: () => Promise<T>): Promise<T> {
    performance.mark(`${name}:start`);
    return fn().finally(() => {
      performance.mark(`${name}:end`);
      performance.measure(name, `${name}:start`, `${name}:end`);
    });
  }

  async getPerformanceMetrics(): Promise<any> {
    const cachedMetrics = await this.cacheService.get('performance:metrics');
    if (cachedMetrics) return cachedMetrics;

    const entries = await this.cacheService.getKeysByPattern('performance:*');
    const metrics = await Promise.all(
      entries.map(async (key) => {
        const data = await this.cacheService.get(key);
        return data;
      }),
    );

    // Store aggregated metrics in cache
    await this.cacheService.set('performance:metrics', metrics, this.cacheTTL);
    return metrics;
  }

  async getSlowestOperations(limit = 10): Promise<any[]> {
    const metrics = await this.getPerformanceMetrics();
    return metrics
      .sort((a, b) => b.duration - a.duration)
      .slice(0, limit);
  }

  async getAverageResponseTime(): Promise<number> {
    const metrics = await this.getPerformanceMetrics();
    const durations = metrics.map((m) => m.duration);
    return durations.reduce((sum, dur) => sum + dur, 0) / durations.length;
  }

  async getApiPerformance(): Promise<any> {
    const metrics = await this.getPerformanceMetrics();
    const apiMetrics = metrics.filter((m) => m.name.startsWith('api:'));
    return {
      count: apiMetrics.length,
      average: this.getAverageResponseTime(),
      slowest: await this.getSlowestOperations(),
    };
  }
}
