export enum LogLevel {
  DEBUG = 'debug',
  INFO = 'info',
  WARN = 'warn',
  ERROR = 'error',
}

export interface LogEntry {
  timestamp: string;
  level: LogLevel;
  message: string;
  details?: any;
}

export interface Metrics {
  totalEmailsSent: number;
  successfulEmails: number;
  failedEmails: number;
  averageSendTime: number;
  lastError?: LogEntry;
}

export class Logger {
  private static instance: Logger;
  private logLevel: LogLevel = LogLevel.INFO;
  private logs: LogEntry[] = [];
  private metrics: Metrics = {
    totalEmailsSent: 0,
    successfulEmails: 0,
    failedEmails: 0,
    averageSendTime: 0,
  };
  private startTime?: number;

  private constructor() {}

  static getInstance(): Logger {
    if (!Logger.instance) {
      Logger.instance = new Logger();
    }
    return Logger.instance;
  }

  setLogLevel(level: LogLevel): void {
    this.logLevel = level;
  }

  debug(message: string, details?: any): void {
    this.log(LogLevel.DEBUG, message, details);
  }

  info(message: string, details?: any): void {
    this.log(LogLevel.INFO, message, details);
  }

  warn(message: string, details?: any): void {
    this.log(LogLevel.WARN, message, details);
  }

  error(message: string, details?: any): void {
    this.log(LogLevel.ERROR, message, details);
    this.metrics.lastError = {
      timestamp: new Date().toISOString(),
      level: LogLevel.ERROR,
      message,
      details,
    };
  }

  private log(level: LogLevel, message: string, details?: any): void {
    if (this.shouldLog(level)) {
      const entry: LogEntry = {
        timestamp: new Date().toISOString(),
        level,
        message,
        details,
      };
      this.logs.push(entry);
      console.log(`[${entry.timestamp}] ${level.toUpperCase()}: ${message}`, details || '');
    }
  }

  private shouldLog(level: LogLevel): boolean {
    const levels = Object.values(LogLevel);
    return levels.indexOf(level) >= levels.indexOf(this.logLevel);
  }

  startOperation(): void {
    this.startTime = Date.now();
  }

  endOperation(success: boolean): void {
    if (this.startTime) {
      const duration = Date.now() - this.startTime;
      this.metrics.totalEmailsSent++;
      if (success) {
        this.metrics.successfulEmails++;
      } else {
        this.metrics.failedEmails++;
      }
      this.metrics.averageSendTime =
        (this.metrics.averageSendTime * (this.metrics.totalEmailsSent - 1) + duration) /
        this.metrics.totalEmailsSent;
      this.startTime = undefined;
    }
  }

  getMetrics(): Metrics {
    return { ...this.metrics };
  }

  getLogs(level?: LogLevel): LogEntry[] {
    if (level) {
      return this.logs.filter(log => log.level === level);
    }
    return [...this.logs];
  }

  clearLogs(): void {
    this.logs = [];
  }

  resetMetrics(): void {
    this.metrics = {
      totalEmailsSent: 0,
      successfulEmails: 0,
      failedEmails: 0,
      averageSendTime: 0,
    };
  }

  /**
   * Create a standardized log entry for email operations
   * @param operation - The email operation being performed
   * @param success - Whether the operation was successful
   * @param details - Additional details about the operation
   */
  logEmailOperation(operation: string, success: boolean, details?: any): void {
    const level = success ? LogLevel.INFO : LogLevel.ERROR;
    const message = `${operation} ${success ? 'completed successfully' : 'failed'}`;
    this.log(level, message, details);
  }
}
