import {
  UserManager,
  WebStorageStateStore,
  User,
  UserManagerSettings,
} from 'oidc-client';
import Vue from 'vue';
import store from '@state/store';
import { messageBroadcast } from '@utils/broadcast';
import { USER_SCOPES } from '@constants/entities/Scope';

export default class AuthService {
  private user: User | null = null;
  private userManager: UserManager;

  constructor() {
    const STS_DOMAIN = Vue.prototype.$appConfig.authority;
    const scope: USER_SCOPES[] = Object.values(USER_SCOPES);
    const settings: UserManagerSettings = {
      userStore: new WebStorageStateStore({ store: window.localStorage }),
      authority: STS_DOMAIN,
      client_id: 'arm',
      redirect_uri: `${origin}${
        process.env.VUE_APP_PROJECT_PATH || ''
      }/callback`,
      automaticSilentRenew: true,
      silent_redirect_uri: `${origin}${
        process.env.VUE_APP_PROJECT_PATH || ''
      }/silent-renew`,
      response_type: 'code',
      response_mode: 'query',
      scope: scope.join(' '),
      // additionalUrlPath - Это костыль для редиректа на разные методы входа для front-idm-micro
      post_logout_redirect_uri: `${document.location.origin}${
        process.env.VUE_APP_PROJECT_PATH || ''
      }${sessionStorage.getItem('additionalUrlPath') || ''}`,
      filterProtocolClaims: true,
      // offset for waiting before renew token by timeout (see accessTokenExpiringNotificationTime).
      silentRequestTimeout: process.env.VUE_APP_AUTH_SILENT_TIMEOUT || 0,
    };

    this.userManager = new UserManager(settings);

    this.userManager.events.addUserLoaded((user) => {
      this.user = user;
    });
    this.userManager.events.addSilentRenewError((e) => {
      store.dispatch('utils/error/error', e);
      this.logout().then(() => {
        this.user = null;
        this.login();
      });
    });
    this.userManager.events.addUserUnloaded(() => {
      messageBroadcast({
        oidcClient: {
          action: 'relogin',
        },
      });
    });
  }

  public async getUser(): Promise<User | null> {
    if (this.user) return Promise.resolve(this.user);
    else {
      const a = await this.userManager.getUser();
      return a;
    }
  }

  public setUser(user: User | null): void {
    this.user = user;
  }

  public isAuthorized(): boolean {
    return !!this.user && !this.user.expired;
  }

  public login(): Promise<void> {
    return this.userManager.signinRedirect();
  }

  /**
   * oidc-client specific callback. {@see UserManagerSettings.redirect_uri}
   */
  public loginCallback(): void {
    // TODO: правильней бы было продумать как определять стартовый location
    // каким-то образом в зависимости от пользователя, его ролей или организации.
    const defaultRouteMap: { [key: string] : string } = {
      '/ervu': '/start',
      '/microws': '/start',
      // '/redesign': '/statements',      
      // '/alpha': '/statements',
      // '/beta': '/statements'
    }
    // @ts-ignore
    const defaultRoute = defaultRouteMap[process.env.VUE_APP_PROJECT_PATH] || '/statements';
    this.userManager.signinRedirectCallback().then(() => {
      window.location.href = process.env.VUE_APP_PROJECT_PATH  + defaultRoute  || '/';
    });
  }

  /**
   * need for silent renew token by timeout {@see UserManagerSettings.silentRequestTimeout}
   */
  public loginSilentRenew(): void {
    this.userManager
      .signinSilentCallback()
      .catch((e) =>
        store.dispatch('utils/error/error', ['_SILENT-RENEW.catch', e])
      );
  }

  public logout(): Promise<void> {
    return this.userManager.signoutRedirect();
  }

  public getAccessToken(): Promise<string> {
    return this.userManager.getUser().then((data: any) => {
      return data?.access_token;
    });
  }
}

/**
 * @singleton auth
 */
export const auth = new AuthService();
