/*
 * Copyright (C) 2019 Robert Bosch GmbH Copyright (C) 2019 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Inject, Injectable } from '@angular/core';
import { Observable, ReplaySubject, Subject } from 'rxjs';
import { CoreConfig } from '../core-configuration/core-config';
import { CORE_CONFIG } from '../core-configuration/core-config.token';
import { LoggerService } from './logger.service';
import { LogLevel } from './loglevel';
import { LogObject } from './logobject';

@Injectable({
  providedIn: 'root',
})
export class ConsoleLoggerService implements LoggerService {
  public logLevel: LogLevel = LogLevel.INFORMATION;

  private _messages$: Subject<LogObject> = new ReplaySubject<LogObject>(10);

  constructor(@Inject(CORE_CONFIG) private coreConfig: CoreConfig) {}

  get messages$(): Observable<LogObject> {
    return this._messages$.asObservable();
  }

  log(level: LogLevel, message: string, error?: Error) {
    if (this.logLevel <= level) {
      const logObject = this.getLogObject(level, message, error);
      if (level >= LogLevel.ERROR) {
        console.error(logObject.toString(), logObject);
      } else if (level === LogLevel.WARN) {
        console.warn(logObject.toString(), logObject);
      } else {
        console.log(logObject.toString(), logObject);
      }

      this._messages$.next(logObject);
    }
  }

  trace(message: string, error?: Error) {
    this.log(LogLevel.TRACE, message, error);
  }

  debug(message: string, error?: Error) {
    this.log(LogLevel.DEBUG, message, error);
  }

  info(message: string, error?: Error) {
    this.log(LogLevel.INFORMATION, message, error);
  }

  warn(message: string, error?: Error) {
    this.log(LogLevel.WARN, message, error);
  }

  error(message: string, error?: Error) {
    this.log(LogLevel.ERROR, message, error);
  }

  critical(message: string, error?: Error) {
    this.log(LogLevel.CRITICAL, message, error);
  }

  private getLogObject(level: LogLevel, message: string, error?: Error): LogObject {
    return Object.assign(new LogObject(), <LogObject>{
      timestamp: new Date(),
      loglevel: LogLevel[level],
      message: message,
      environment: this.coreConfig.environment,
      error: error,
    });
  }
}
