import type { ILogger, LogContext, LogLevel } from '../../../application/ports/ILogger';
import { loadLoggingConfig, type LoggingEnvironmentConfig } from '../../config/LoggingConfig';

const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
  debug: 10,
  info: 20,
  warn: 30,
  error: 40,
  fatal: 50,
};

/**
 * PinoLogAdapter - Electron-compatible logger implementation.
 *
 * Note: We use a custom console-based implementation instead of pino
 * because pino's internal use of diagnostics_channel.tracingChannel
 * is not compatible with Electron's Node.js version.
 *
 * This provides structured JSON logging to stdout with the same interface.
 */
export class PinoLogAdapter implements ILogger {
  private readonly config: LoggingEnvironmentConfig;
  private readonly baseContext: LogContext;
  private readonly levelPriority: number;

  constructor(config?: LoggingEnvironmentConfig, baseContext?: LogContext) {
    this.config = config || loadLoggingConfig();
    this.baseContext = {
      app: 'gridpilot-companion',
      version: process.env.npm_package_version || '0.0.0',
      processType: process.type || 'main',
      ...baseContext,
    };
    this.levelPriority = LOG_LEVEL_PRIORITY[this.config.level];
  }

  private shouldLog(level: LogLevel): boolean {
    return LOG_LEVEL_PRIORITY[level] >= this.levelPriority;
  }

  private formatLog(level: LogLevel, message: string, context?: LogContext, error?: Error): string {
    const entry: Record<string, unknown> = {
      level,
      time: new Date().toISOString(),
      ...this.baseContext,
      ...context,
      msg: message,
    };

    if (error) {
      entry.err = {
        message: error.message,
        name: error.name,
        stack: error.stack,
      };
    }

    return JSON.stringify(entry);
  }

  private log(level: LogLevel, message: string, context?: LogContext, error?: Error): void {
    if (!this.shouldLog(level)) {
      return;
    }

    const output = this.formatLog(level, message, context, error);

    if (this.config.prettyPrint) {
      const timestamp = new Date().toLocaleString();
      const levelColors: Record<LogLevel, string> = {
        debug: '\x1b[36m', // cyan
        info: '\x1b[32m',  // green
        warn: '\x1b[33m',  // yellow
        error: '\x1b[31m', // red
        fatal: '\x1b[35m', // magenta
      };
      const reset = '\x1b[0m';
      const color = levelColors[level];
      
      const contextStr = context ? ` ${JSON.stringify(context)}` : '';
      const errorStr = error ? `\n  ${error.stack || error.message}` : '';
      
      console.log(`${color}[${timestamp}] ${level.toUpperCase()}${reset}: ${message}${contextStr}${errorStr}`);
    } else {
      console.log(output);
    }
  }

  debug(message: string, context?: LogContext): void {
    this.log('debug', message, context);
  }

  info(message: string, context?: LogContext): void {
    this.log('info', message, context);
  }

  warn(message: string, context?: LogContext): void {
    this.log('warn', message, context);
  }

  error(message: string, error?: Error, context?: LogContext): void {
    this.log('error', message, context, error);
  }

  fatal(message: string, error?: Error, context?: LogContext): void {
    this.log('fatal', message, context, error);
  }

  child(context: LogContext): ILogger {
    return new PinoLogAdapter(this.config, { ...this.baseContext, ...context });
  }

  async flush(): Promise<void> {
    // Console output is synchronous, nothing to flush
  }
}