import {
  Logger,
  LogLevel,
  LogMessage,
  LogObject,
  LogOutput,
  LogSerializer,
} from 'tachyon-logger/logger';
import { LoggerMiddleware } from 'tachyon-logger/loggerMiddleware';

/**
 * An abstract logger that will apply transformations to logged content.
 */
export abstract class AbstractLogger implements Logger {
  /**
   * @param middleware  An array of transformation functions to apply to all
   *                    log output.
   */
  constructor(
    protected middleware: LoggerMiddleware[],
    protected serializer: LogSerializer = obj => obj,
  ) {}

  public abstract debug(message: LogMessage): void;
  public abstract log(message: LogMessage): void;
  public abstract info(message: LogMessage): void;
  public abstract warn(message: LogMessage): void;
  public abstract error(message: LogMessage): void;

  protected getLogOutput(level: LogLevel, message: LogMessage): LogOutput {
    return this.serializer(this.getLogObject(level, message));
  }

  /**
   * Apply all transformations to the log message and return the final object
   * to be logged.
   *
   * @param level    The severity of the log.
   * @param message  The original content to log. By default, this will be
   *                 stored in message.
   */
  protected getLogObject(level: LogLevel, message: LogMessage): LogObject {
    return this.middleware.reduce(
      (previousTransformation, transformer) => {
        return transformer(previousTransformation);
      },
      {
        level, // level should always be last here for console readability
        message, // message should be first here for console readability
        time: Date.now(),
      } as LogObject,
    );
  }
}
