import { HttpClient } from 'aurelia-fetch-client';
import { Aurelia, inject } from "aurelia-framework";
import { Router } from "aurelia-router";
import { Datacontext } from '../data/data-context';
import { Config } from '../config';
import { SigninRedirectArgs, UserManager } from 'oidc-client-ts';
import { BaseOAuthService, OAuthClientWrapper } from './oauth-service';
import { LoginMsg } from './login-msg';

class DWAuthClientWrapper extends OAuthClientWrapper {
  private client: UserManager;

  public async init() {
    this.client = new UserManager({
      authority: 'https://' + this.config.domain,
      client_id: this.config.clientId,
      client_secret: this.config.clientSecret,
      redirect_uri: this.config.callback_uri,
      scope: "openid offline_access",
      automaticSilentRenew: true,
      //TODO?
      //userStore: new WebStorageStateStore({ store: window.localStorage })
    });
    this.client.events.addSilentRenewError(() => this.logout());
    return this;
  }

  public async accessToken(): Promise<string> {
    let user = await this.client.getUser();
    return user ? user.access_token : null;
  }

  public loginWithRedirect(loginMsg: LoginMsg = null) {
    let signinRedirectArgs: SigninRedirectArgs = { redirect_uri: this.config.callback_uri };
    if (loginMsg) {
      let obj = {};
      obj[loginMsg.theme + "_msg"] = loginMsg.msgToDisplayOnLoginPage;
      signinRedirectArgs.extraQueryParams = obj;
    }
    return this.client.signinRedirect(signinRedirectArgs);
  }

  public async handleSignInRedirect(): Promise<void> {
    await this.client.signinRedirectCallback();
  }

  public async isAuthenticated(): Promise<boolean> {
    let user = await this.client.getUser();
    return user?.expired === false;
  }

  public async logout(): Promise<void> {
    await this.client.removeUser();
    await this.client.signoutRedirect({ post_logout_redirect_uri: this.config.logout_uri });
  }

  public async getUserProfile(): Promise<any> {
    return (await this.client.getUser()).profile;
  }

  public async onUserPermissionsChanged(): Promise<void> {
    await this.client.removeUser();
    sessionStorage.setItem('location', JSON.stringify({ url: location.pathname }));
    await this.loginWithRedirect();
  }
}

@inject(Router, Aurelia, Datacontext, Config, HttpClient)
export class DWAuthService extends BaseOAuthService<DWAuthClientWrapper> {

  constructor(router: Router, app: Aurelia, dataContext: Datacontext, config: Config, httpClient: HttpClient) {
    super(router, app, dataContext, config, httpClient);
  }

  protected makeClient(): Promise<DWAuthClientWrapper> {
    return new DWAuthClientWrapper(this.config.authConfig).init();
  }

  public async loginWithRedirect(navInstruction: string, loginMsg: LoginMsg = null) {
    sessionStorage.setItem('location', JSON.stringify({ url: navInstruction }));
    (await this.makeClient()).loginWithRedirect(loginMsg);
  }

  public get usernameType(): "email" | "username" {
    return "username";
  }

  public async onUserPermissionsChanged(): Promise<void> {
    let client = await this.getClient();
    await client.onUserPermissionsChanged();
  }
}
