/**
 * Logging utilities for GitOps
 */

import type { ISyncLogEntry } from '../ts_interfaces/data/sync.ts';

type LogLevel = 'info' | 'success' | 'warn' | 'error' | 'debug';

const SYNC_LOG_MAX = 500;

class Logger {
  private debugMode = false;
  private syncLogBuffer: ISyncLogEntry[] = [];
  private broadcastFn?: (entry: ISyncLogEntry) => void;

  constructor() {
    this.debugMode = Deno.args.includes('--debug') || Deno.env.get('DEBUG') === 'true';
  }

  /**
   * Set the broadcast function used to push sync log entries to connected clients.
   */
  setBroadcastFn(fn: (entry: ISyncLogEntry) => void): void {
    this.broadcastFn = fn;
  }

  /**
   * Log a sync-related message to both the console and the ring buffer.
   * Also broadcasts to connected frontends via TypedSocket if available.
   */
  syncLog(level: ISyncLogEntry['level'], message: string, source?: string): void {
    // Also log to console
    this.log(level, message);

    const entry: ISyncLogEntry = {
      timestamp: Date.now(),
      level,
      message,
      source,
    };

    this.syncLogBuffer.push(entry);
    if (this.syncLogBuffer.length > SYNC_LOG_MAX) {
      this.syncLogBuffer.splice(0, this.syncLogBuffer.length - SYNC_LOG_MAX);
    }

    if (this.broadcastFn) {
      this.broadcastFn(entry);
    }
  }

  /**
   * Get recent sync log entries.
   */
  getSyncLogs(limit = 100): ISyncLogEntry[] {
    return this.syncLogBuffer.slice(-limit);
  }

  log(level: LogLevel, message: string, ...args: unknown[]): void {
    const prefix = this.getPrefix(level);
    const formattedMessage = `${prefix} ${message}`;

    switch (level) {
      case 'error':
        console.error(formattedMessage, ...args);
        break;
      case 'warn':
        console.warn(formattedMessage, ...args);
        break;
      case 'debug':
        if (this.debugMode) {
          console.log(formattedMessage, ...args);
        }
        break;
      default:
        console.log(formattedMessage, ...args);
    }
  }

  info(message: string, ...args: unknown[]): void {
    this.log('info', message, ...args);
  }

  success(message: string, ...args: unknown[]): void {
    this.log('success', message, ...args);
  }

  warn(message: string, ...args: unknown[]): void {
    this.log('warn', message, ...args);
  }

  error(message: string, ...args: unknown[]): void {
    this.log('error', message, ...args);
  }

  debug(message: string, ...args: unknown[]): void {
    this.log('debug', message, ...args);
  }

  private getPrefix(level: LogLevel): string {
    const colors: Record<LogLevel, string> = {
      info: '\x1b[36m',
      success: '\x1b[32m',
      warn: '\x1b[33m',
      error: '\x1b[31m',
      debug: '\x1b[90m',
    };
    const reset = '\x1b[0m';
    const icons: Record<LogLevel, string> = {
      info: 'i',
      success: '+',
      warn: '!',
      error: 'x',
      debug: '*',
    };
    return `${colors[level]}[${icons[level]}]${reset}`;
  }
}

export const logger = new Logger();
