import winston from 'winston';
import { Config } from '../config/config.js';

export class Logger {
  private logger: winston.Logger;
  private component: string;

  constructor(component: string) {
    this.component = component;
    this.logger = this.createLogger();
  }

  private createLogger(): winston.Logger {
    const config = Config.getInstance();
    const logConfig = config.logging;

    const transports: winston.transport[] = [
      new winston.transports.Console({
        format: winston.format.combine(
          winston.format.colorize(),
          winston.format.timestamp(),
          winston.format.printf(({ timestamp, level, message, component, ...meta }) => {
            const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : '';
            return `${timestamp} [${level}] [${component || this.component}] ${message}${metaStr}`;
          })
        )
      })
    ];

    if (logConfig.file) {
      transports.push(
        new winston.transports.File({
          filename: logConfig.file,
          format: winston.format.combine(
            winston.format.timestamp(),
            winston.format.json()
          )
        })
      );
    }

    return winston.createLogger({
      level: logConfig.level,
      defaultMeta: { component: this.component },
      transports,
      exceptionHandlers: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.colorize(),
            winston.format.simple()
          )
        })
      ],
      rejectionHandlers: [
        new winston.transports.Console({
          format: winston.format.combine(
            winston.format.colorize(),
            winston.format.simple()
          )
        })
      ]
    });
  }

  public debug(message: string, meta?: any): void {
    this.logger.debug(message, meta);
  }

  public info(message: string, meta?: any): void {
    this.logger.info(message, meta);
  }

  public warn(message: string, meta?: any): void {
    this.logger.warn(message, meta);
  }

  public error(message: string, meta?: any): void {
    this.logger.error(message, meta);
  }

  public setLevel(level: string): void {
    this.logger.level = level;
  }

  public child(childComponent: string): Logger {
    return new Logger(`${this.component}:${childComponent}`);
  }
}