import { Injectable } from '@angular/core';
import { Config } from '@core/config';
import { isNullOrUndefined } from '@utils/common';
import { AuthConfig, OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  private readonly _initialized = new BehaviorSubject<boolean>(false);
  get initialized$() {
    return this._initialized.asObservable();
  }

  constructor(private _config: Config, private readonly _oAuthService: OAuthService) {}

  async init() {
    if (this._initialized.getValue()) {
      throw new Error('AuthService is already initialized');
    }

    const authConfig: AuthConfig = this._config.get('@core/auth');

    authConfig.redirectUri = window.location.origin;
    authConfig.silentRefreshRedirectUri = window.location.origin + '/silent-refresh.html';
    authConfig.useSilentRefresh = true;

    this._oAuthService.configure(authConfig);
    this._oAuthService.tokenValidationHandler = new JwksValidationHandler();

    this._oAuthService.setupAutomaticSilentRefresh();
    await this._oAuthService.loadDiscoveryDocumentAndTryLogin();

    this._initialized.next(true);
  }

  isAuthenticated() {
    return this._oAuthService.hasValidIdToken();
  }

  getToken() {
    return this._oAuthService.getAccessToken();
  }

  getClaims() {
    const token = this._oAuthService.getAccessToken();
    return this.parseJwt(token);
  }

  getClaimByKey(key: string) {
    const claims = this.getClaims();
    if (isNullOrUndefined(claims)) {
      return null;
    }
    return claims[key];
  }

  parseJwt(token: string) {
    if (isNullOrUndefined(token)) {
      return null;
    }
    const base64Url = token.split('.')[1];
    const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');

    const encoded = window.atob(base64);
    return JSON.parse(encoded);
  }

  login() {
    this._oAuthService.initLoginFlow();
  }

  setKeyCardToken(token: string) {
    this._oAuthService.customQueryParams = {
      temp_token: token,
    };
  }

  async logout() {
    await this._oAuthService.revokeTokenAndLogout();
  }
}
