import { Injectable, Inject } from '@angular/core';

import { Store } from '@ngrx/store';

import { DeviceType, DesktopType } from '@ucap/core';
import { NativeService, NativeType, OsType } from '@ucap/native';

import { I18nService } from '@ucap/ng-i18n';
import { LogService } from '@ucap/ng-logger';
import { UCAP_NATIVE_SERVICE } from '@ucap/ng-native';
import { PingProtocolService } from '@ucap/ng-protocol-ping';
import { DateService } from '@ucap/ng-ui';
import { TranslateService } from '@ucap/ng-ui-organization';
import { ProtocolService } from '@ucap/ng-protocol';
import { LoginActions } from '@ucap/ng-store-authentication';

import { environment } from '@environments';

import { AppAuthenticationService } from './app-authentication.service';
import { take } from 'rxjs/operators';

@Injectable()
export class AppService {
  readonly companyGroupCode = environment.companyConfig.companyGroupCode;

  constructor(
    private i18nService: I18nService,
    private translateService: TranslateService,
    private dateService: DateService,
    private protocolService: ProtocolService,
    private pingProtocolService: PingProtocolService,
    private appAuthenticationService: AppAuthenticationService,
    private logService: LogService,
    private store: Store<any>,
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService
  ) {}

  initialize(): Promise<void[]> {
    const initSession = new Promise<void>(async (resolve, reject) => {
      try {
        let loginSession = this.appAuthenticationService.getLoginSession();

        loginSession = loginSession || {};

        let deviceType: DeviceType;
        let desktopType: DesktopType;

        switch (this.nativeService.type()) {
          case NativeType.Browser:
            deviceType = DeviceType.Web;
            break;
          case NativeType.Electron:
            deviceType = DeviceType.PC;
            break;
          default:
            break;
        }

        const osType = await this.nativeService.osType();

        switch (osType) {
          case OsType.Windows:
            desktopType = DesktopType.Windows;
            break;
          case OsType.MacOS:
            desktopType = DesktopType.MacOS;
            break;
          default:
            desktopType = DesktopType.Linux;
            break;
        }

        this.appAuthenticationService.setLoginSession({
          ...loginSession,
          deviceType,
          desktopType,
          companyGroupCode: this.companyGroupCode,
          alive: false
        });

        this.dateService.setDefaultTimezone('Asia/Seoul');
        this.dateService.use('Asia/Seoul');

        resolve();
      } catch (error) {
        reject(error);
      }
    });

    const initI18n = new Promise<void>(async (resolve, reject) => {
      switch (this.nativeService.type()) {
        case NativeType.Browser:
          const xhr = await import('i18next-xhr-backend').then(
            (m) => m.default
          );
          const languageDetector = await import(
            'i18next-browser-languagedetector'
          ).then((m) => m.default);
          this.i18nService.use(xhr).use(languageDetector);
          break;
        // case NativeType.Electron:
        //   const nodeFs = await import('i18next-node-fs-backend').then(m => m);
        //   i18nService.use(nodeFs);
        //   break;
        default:
          break;
      }

      this.i18nService
        .init({
          whitelist: ['ko', 'en'],
          fallbackLng: 'ko',
          debug: true, // set debug?
          returnEmptyString: false,
          ns: [
            'common',
            'organization',
            'authentication',
            'group',
            'chat',
            'call',
            'message'
          ],
          backend: {
            loadPath: 'assets/i18n/{{lng}}/{{ns}}.json'
          }
        })
        .then(() => {
          this.dateService.setLocale(this.i18nService.currentLng);

          resolve();
        })
        .catch((reason) => {
          reject(reason);
        });
    });

    const initOrganization = new Promise<void>(async (resolve, reject) => {
      try {
        this.translateService.setDefaultLang('ko');
        this.translateService.use('ko');
        resolve();
      } catch (error) {
        reject(error);
      }
    });

    const initProtocol = new Promise<void>(async (resolve, reject) => {
      try {
        this.protocolService.connected$.subscribe((connected) => {
          if (undefined === connected) {
            return;
          }
          if (connected) {
            this.appAuthenticationService
              .createSession()
              .then((result) => {
                this.store.dispatch(
                  LoginActions.sessionCreated({
                    res: result.loginRes,
                    loginSession: result.loginSession
                  })
                );
              })
              .catch((reason) => {
                this.logService.error('createSession failed', reason);
              });
          } else {
            this.store.dispatch(
              LoginActions.sessionDestroyed({ error: 'disconnected' })
            );
          }
        });
        resolve();
      } catch (error) {
        reject(error);
      }
    });

    return Promise.all([initSession, initI18n, initOrganization, initProtocol]);
  }
}
