import { Inject, Injectable } from '@angular/core';
import * as Utils from '../utils';
import { MatDialogService } from './mat-dialog.service';
import { MessageBoxComponent } from '../components/message-box/message-box.component';
import { EN_LogType } from '../consts';
import { Globals, IMessageBoxButton, IMessageBoxData } from './globals';
import * as Sentry from '@sentry/angular';
import { ENVIRONMENT_TOKEN, IENVIRONMENT } from '../injection-tokens';
import { HenselTranslateService } from './localization/hensel-translate.service';
import { MatDialogRef } from '../components/angular-material-index';

const DoubledEventIntrval = 500;

@Injectable({
  providedIn: 'root'
})

export class AppLogsService {
  startingTimes: Map<string, number> = new Map();
  constructor(
    private dialog: MatDialogService,
    private globals: Globals,
    public translate: HenselTranslateService,
    @Inject(ENVIRONMENT_TOKEN) private environment: IENVIRONMENT,
  ) { }

  checkDoubledEvent(key: string) {
    const nowticks = Utils.now();
    const isDoubled = (this.startingTimes.has(key) && (nowticks - this.startingTimes.get(key)) < DoubledEventIntrval);
    this.startingTimes.set(key, nowticks);
    return isDoubled;
  }

  log(message?: any, ...optionalParams: any[]) {
    this._log(EN_LogType.message, message, ...optionalParams);
  }

  warn(message?: any, ...optionalParams: any[]) {
    this._log(EN_LogType.warning, message, ...optionalParams);
  }

  error(message?: any, ...optionalParams: any[]) {
    this._log(EN_LogType.error, message, ...optionalParams);
    const err = optionalParams.find(obj => typeof obj === 'object');
    if (this.environment.sentry_dsn) Sentry.captureException(err ?? message);
  }


  exception(exception: any, ...optionalParams: any[]) {
    this._log(EN_LogType.error, Utils.getErrorMessageAsText(exception), ...optionalParams);
    if (this.environment.sentry_dsn) Sentry.captureException(Utils.extractError(exception));
  }


  dlog(message?: any, ...optionalParams: any[]) {
    this._log(EN_LogType.debug_message, message, ...optionalParams);
  }


  private _log(logType: EN_LogType, message?: any, ...optionalParams: any[]) {
    let timestr: string = '';
    let guid: string = null;
    const isDebug = logType === EN_LogType.debug_message;
    const guiindex = optionalParams.findIndex(
      obj => { if (typeof obj === 'object' && 'guid' in obj) { guid = obj.guid; return true; } else return false; }
    );


    if (guid) {
      optionalParams.splice(guiindex, 1);
      if (this.startingTimes.has(guid)) {
        timestr = Utils.ms2ToTimeString(Utils.now() - this.startingTimes.get(guid), 'm:s.SSS');
        this.startingTimes.delete(guid);
        logType = EN_LogType.guid_message;
      } else this.startingTimes.set(guid, Utils.now());
    }
    switch (logType) {
      case EN_LogType.message:
        console.log(message, ...optionalParams);
        break;
      case EN_LogType.warning:
        console.warn(message, ...optionalParams);
        break;
      case EN_LogType.error:
        console.error(message, ...optionalParams);
        break;
      case EN_LogType.debug_message:
        if (!this.environment.production) console.log(message, ...optionalParams);
        break;
      case EN_LogType.guid_message:
        if (!isDebug || !this.environment.production) {
          console.log('Finished: ' + ((<string>message).indexOf('%c') > -1 ? '' : '%c') + message + (timestr ? ': ' + timestr + 's' : ''), ...optionalParams);
        }
        break;
    }
  }

  showMessageBox(messageBoxData: IMessageBoxData, callBack?: () => void): MatDialogRef<unknown, any> {
    messageBoxData.overHeader = this.globals.appTitleWithVersion;
    // messageBoxData.header = Utils.translateString(messageBoxData.header, this.translate);
    // messageBoxData.message = Utils.translateString(messageBoxData.message, this.translate);
    return this.dialog.openDialog(MessageBoxComponent, messageBoxData, true, (result: number) => {
      if (callBack) callBack();
      messageBoxData.buttons.forEach((btn: IMessageBoxButton) => {
        if (btn.code === result && btn.callback) btn.callback();
      });
    }, false);
  }


  errorMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef<unknown, any> {
    return this.showMessageBox(<IMessageBoxData>{
      type: EN_LogType.error,
      header: caption,
      message: message,
      buttons: [{ title: this.translate.instant('core.btn.ok') }]
    }, commonCallBack);
  }


  warningMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef<unknown, any> {
    return this.showMessageBox(<IMessageBoxData>{
      type: EN_LogType.warning,
      header: caption,
      message: message,
      buttons: [{ title: this.translate.instant('core.btn.ok') }]
    }, commonCallBack);
  }


  informationMessageBox(caption: string, message: string, commonCallBack?: () => void): MatDialogRef<unknown, any> {
    return this.showMessageBox(<IMessageBoxData>{
      type: EN_LogType.message,
      header: caption,
      message: message,
      buttons: [{ title: this.translate.instant('core.btn.ok') }]
    }, commonCallBack);
  }


  confirmMessageBoxYesNo(caption: string, message: string, yesCallBack: () => void, commonCallBack?: () => void, defaultButtonInx: number = 0): MatDialogRef<unknown, any> {
    return this.showMessageBox(<IMessageBoxData>{
      type: EN_LogType.confirmation,
      header: caption,
      message: message,
      buttons: [{ title: this.translate.instant('core.btn.yes'), code: 1, default: defaultButtonInx === 0, callback: yesCallBack },
      { title: this.translate.instant('core.btn.no'), default: defaultButtonInx === 1, cancel: true, code: 0 },
      ]
    }, commonCallBack);
  }


  confirmMessageBoxYesNoCancel(caption: string, message: string, yesCallBack: () => void, noCallBack: () => void, commonCallBack?: () => void, defaultButtonInx: number = 0): MatDialogRef<unknown, any> {
    return this.showMessageBox(<IMessageBoxData>{
      type: EN_LogType.confirmation,
      header: caption,
      message: message,
      buttons: [{ title: this.translate.instant('core.btn.yes'), code: 1, callback: yesCallBack, default: defaultButtonInx === 0 },
      { title: this.translate.instant('core.btn.no'), code: 0, callback: noCallBack, default: defaultButtonInx === 1 },
      { title: this.translate.instant('core.btn.cancel'), cancel: true, code: -1, default: defaultButtonInx === 2 },
      ]
    }, commonCallBack);
  }
}
