import { inject, Injectable } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { BehaviorSubject, interval, Subscription } from 'rxjs';
import { EN_LoginStatus } from '../consts';
import { Globals } from './globals';
import { APPICON4LIVE_TOKEN, APPICON4TEST_TOKEN, ENVIRONMENT_TOKEN } from '../injection-tokens';
import { ServerInfo } from '../models/serverinfo';
import { setIndexIcon } from '../utils';
import { AppLogsService } from './applogs.service';
import { AuthorizeService } from './authorize.service';
import { RepositoryService } from './http/repository.service';
import { HenselTranslateService } from './localization/hensel-translate.service';
import { MatDialogRef } from '../components/angular-material-index';

const cnstPollingInterval1stInSec = 3;
const cnstPollingIntervalConnectedInSec = 15;
const time4TimeoutMessageInSec = 10;

const enum EN_ServerStates {
  Offline = -1,
  Live = 0,
  Development = 1,
}


@Injectable({ providedIn: 'root' })

export class ServerInfoService {
  private environment = inject(ENVIRONMENT_TOKEN);
  public serverInfo: ServerInfo = new ServerInfo();
  public serverStatus: EN_ServerStates = EN_ServerStates.Offline;
  public defaultServerInfoVisible: boolean = true;
  public serverInfoVisible: boolean;
  protected pollingItervalTimer: Subscription = null;
  public connectionReady: BehaviorSubject<ServerInfo> = new BehaviorSubject<ServerInfo>(null);
  private EN_LoginStatus_Password = EN_LoginStatus.loginWithNameAndPassword;
  private warningTimeOut: any;
  private warningPopup: MatDialogRef<unknown, any>;
  private cnst_AppIcon4Live = inject(APPICON4LIVE_TOKEN);
  private cnst_AppIcon4Test = inject(APPICON4TEST_TOKEN);

  private _pollingIntervalConnectedInSec: number = cnstPollingIntervalConnectedInSec;

  public get pollingIntervalConnectedInSec() {
    return this._pollingIntervalConnectedInSec;
  }
  public set pollingIntervalConnectedInSec(value: number) {
    this._pollingIntervalConnectedInSec = value;
    this.resetPolling(value || 0);
  }

  constructor(
    private serverInfoDataService: RepositoryService,
    public authorizationService: AuthorizeService,
    public globals: Globals,
    private appLogsService: AppLogsService,
    public translate: HenselTranslateService,
    private updateService: SwUpdate,
  ) {
    this.resetPolling(cnstPollingInterval1stInSec);

    this.createWarningTimeOutSubscriber = this.createWarningTimeOutSubscriber.bind(this);
    this.createWarningTimeOutSubscriber();

    this.authorizationService.loginAction$.subscribe((resultObject) => {
      if (resultObject.result) {
        if (this.authorizationService.user.showFooter !== undefined) {
          this.serverInfoVisible = authorizationService.user.showFooter;
        } else {
          if (this.serverInfoVisible === undefined) this.serverInfoVisible = authorizationService.user.isAdmin;
        }
      } else {
        this.serverInfoVisible = this.defaultServerInfoVisible || this.serverInfoVisible;
      }
    });
    this.appLogsService.dlog('Server Info is initialized!');
  }

  createWarningTimeOutSubscriber() {
    this.warningTimeOut = setTimeout(() => {
      clearTimeout(this.warningTimeOut);
      this.warningPopup = this.appLogsService.warningMessageBox(this.translate.instant('core.msgbox.header.connect'), this.translate.instant('core.msgbox.body.connect'), () => this.warningTimeOut = null);
    }, time4TimeoutMessageInSec * 1000);
  }


  resetPolling(intervalInSec: number) {
    if (this.pollingItervalTimer) this.pollingItervalTimer.unsubscribe(); //poll always
    if (intervalInSec > 0) this.pollingItervalTimer = interval(intervalInSec * 1000).subscribe(() => { this.init(); });
  }


  private init() {
    const _isLive = this.serverInfo?.isLive;
    this.resetPolling(0);
    this.serverInfo.firstOnlineTime = this.serverStatus === EN_ServerStates.Offline ? new Date() : null;

    this.serverInfo.save(this.serverInfoDataService, (si: ServerInfo) => {
      this.resetPolling(this.pollingIntervalConnectedInSec);
      if (!this.authorizationService.versionObsolete) this.updateService.checkForUpdate().then(res => this.authorizationService.versionObsolete = this.isOldVersion(this.serverInfo.clientVersion) || res);
      if (si.attributes) {
        si.officeFileServerURL = si.attributes['url'];
        si.officeFileServerVersion = si.attributes['version'];
        si.officeFileServer = si.attributes['server'];
        si.officeFileServerDBServer = si.attributes['databaseserver'];
        si.officeFileServerDBName = si.attributes['databasename'];
      } else {
        si.officeFileServerURL = null;
        si.officeFileServerVersion = null;
        si.officeFileServer = null;
        si.officeFileServerDBServer = null;
        si.officeFileServerDBName = null;
      }

      if (_isLive !== si.isLive) {
        if (si.isLive) {
          setIndexIcon(this.cnst_AppIcon4Live);
          if (this.globals.appTitleWithVersion.startsWith('Test - ')) this.globals.appTitleWithVersion = this.globals.appTitleWithVersion.replace('Test - ', '');
        } else {
          setIndexIcon(this.cnst_AppIcon4Test);
          if (!this.globals.appTitleWithVersion.startsWith('Test - ')) this.globals.appTitleWithVersion = 'Test - ' + this.globals.appTitleWithVersion;
        }
      }

      if (this.serverStatus === EN_ServerStates.Offline) { //first time connection

        if (this.warningPopup) this.warningPopup.close();

        clearTimeout(this.warningTimeOut);
        this.warningTimeOut = null;

        this.appLogsService.dlog('Server connected!');

        this.serverStatus = this.isLive() ? EN_ServerStates.Live : EN_ServerStates.Development;


        if (this.authorizationService.useJWT) {
          // if (!this.authorizationService.checkJWT(this.environment.production ? 60 * 24 /* relogin one day before expiration*/ : 0)) this.authorizationService.loginStatus = this.EN_LoginStatus_Password;
          if (!this.authorizationService.checkJWT(null)) this.authorizationService.loginStatus = this.EN_LoginStatus_Password; //only if there is no JWT
        } else if (!this.authorizationService.useWindowsLogin) this.authorizationService.loginStatus = this.EN_LoginStatus_Password;
        this.connectionReady.next(si);
      }
    }
    , (err) => {
      this.resetPolling(cnstPollingInterval1stInSec);
      if (this.serverStatus !== EN_ServerStates.Offline) {
        this.serverInfo.lastOfflineTime = new Date();
        this.serverStatus = EN_ServerStates.Offline;
      }
      if (!this.warningTimeOut) this.createWarningTimeOutSubscriber();
    }
    , null, '');
  }

  public isOldVersion(mustVersion: string): boolean {
    const isVersion = this.environment.appVersion;
    const checkarrIsVersion = isVersion?.split('.');
    const checkarrMustVersion = mustVersion?.split('.');
    while (checkarrMustVersion.length > checkarrIsVersion.length) checkarrIsVersion.push('0');
    while (checkarrIsVersion.length > checkarrMustVersion.length) checkarrMustVersion.push('0');
    for (let index = 0; index < checkarrIsVersion.length; index++) {
      const isVersionElement = checkarrIsVersion[index];
      const mustVersionElement = checkarrMustVersion[index];
      const isVersionElement_no = Number(isVersionElement);
      const mustVersionElement_no = Number(mustVersionElement);
      if (Number.isNaN(isVersionElement_no) || Number.isNaN(mustVersionElement_no)) {
        if (isVersionElement !== mustVersionElement) return isVersionElement < mustVersionElement;
      } else if (isVersionElement_no !== mustVersionElement_no) return isVersionElement_no < mustVersionElement_no;
    }
    return false;
  }

  public isLive(): boolean {
    return this.serverInfo?.isLive;
  }
}
