import { Injectable } from '@angular/core';

export interface PerformanceMetrics {
  renderTime: number;
  memoryUsage?: number;
  componentCount: number;
  bundleSize?: number;
}

export interface PerformanceThresholds {
  maxRenderTime: number;
  maxMemoryUsage: number;
  maxBundleSize: number;
}

@Injectable({
  providedIn: 'root'
})
export class PerformanceMonitor {
  private metrics: PerformanceMetrics[] = [];
  private thresholds: PerformanceThresholds = {
    maxRenderTime: 50, // ms
    maxMemoryUsage: 50 * 1024 * 1024, // 50MB
    maxBundleSize: 200 * 1024 // 200KB
  };

  /**
   * Record render performance metrics
   */
  recordRenderTime(componentName: string, renderTime: number): void {
    const metric: PerformanceMetrics = {
      renderTime,
      componentCount: 1,
      memoryUsage: this.getMemoryUsage()
    };

    this.metrics.push(metric);
    
    if (renderTime > this.thresholds.maxRenderTime) {
      console.warn(`⚠️ Performance Warning: ${componentName} render time ${renderTime}ms exceeds threshold ${this.thresholds.maxRenderTime}ms`);
    }
  }

  /**
   * Record memory usage
   */
  recordMemoryUsage(componentName: string): void {
    const memoryUsage = this.getMemoryUsage();
    
    if (memoryUsage && memoryUsage > this.thresholds.maxMemoryUsage) {
      console.warn(`⚠️ Memory Warning: ${componentName} memory usage ${this.formatBytes(memoryUsage)} exceeds threshold ${this.formatBytes(this.thresholds.maxMemoryUsage)}`);
    }
  }

  /**
   * Get current memory usage
   */
  private getMemoryUsage(): number | undefined {
    if ('memory' in performance) {
      return (performance as any).memory.usedJSHeapSize;
    }
    return undefined;
  }

  /**
   * Format bytes to human readable
   */
  private formatBytes(bytes: number): string {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * Get performance report
   */
  getPerformanceReport(): {
    averageRenderTime: number;
    maxRenderTime: number;
    memoryUsage: number | undefined;
    totalMetrics: number;
    warnings: string[];
  } {
    if (this.metrics.length === 0) {
      return {
        averageRenderTime: 0,
        maxRenderTime: 0,
        memoryUsage: undefined,
        totalMetrics: 0,
        warnings: []
      };
    }

    const renderTimes = this.metrics.map(m => m.renderTime);
    const averageRenderTime = renderTimes.reduce((a, b) => a + b, 0) / renderTimes.length;
    const maxRenderTime = Math.max(...renderTimes);
    const memoryUsage = this.getMemoryUsage();
    
    const warnings: string[] = [];
    
    if (averageRenderTime > this.thresholds.maxRenderTime) {
      warnings.push(`Average render time ${averageRenderTime.toFixed(2)}ms exceeds threshold ${this.thresholds.maxRenderTime}ms`);
    }
    
    if (memoryUsage && memoryUsage > this.thresholds.maxMemoryUsage) {
      warnings.push(`Memory usage ${this.formatBytes(memoryUsage)} exceeds threshold ${this.formatBytes(this.thresholds.maxMemoryUsage)}`);
    }

    return {
      averageRenderTime,
      maxRenderTime,
      memoryUsage,
      totalMetrics: this.metrics.length,
      warnings
    };
  }

  /**
   * Clear metrics
   */
  clearMetrics(): void {
    this.metrics = [];
  }

  /**
   * Set performance thresholds
   */
  setThresholds(thresholds: Partial<PerformanceThresholds>): void {
    this.thresholds = { ...this.thresholds, ...thresholds };
  }

  /**
   * Check if performance is within budget
   */
  isWithinBudget(): boolean {
    const report = this.getPerformanceReport();
    return report.warnings.length === 0;
  }
}
