import { Injectable } from '@angular/core';
import {Router} from "@angular/router";

const API_TOKEN_KEY = "API_TOKEN";

interface JWTInfo {
  user: string,
  admin: boolean
}

/**
 * Decodes a JWT Token and returns its payload. The JWT Token is **not** checked for validity!
 * @param token jwt token to be
 */
function decodeJWTToken(token : string) : JWTInfo {
  return JSON.parse(atob(token.split(".")[1]));
}


@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private apiToken: string = "";

  constructor(private router: Router) {
    this.reloadToken();
  }

  /**
   * Loads the JWT token from the browsers `localStorgae` (persistent storage) and sets the attribute, if
   * a token exists.
   * @private
   */
  private reloadToken(): void {
    const apiToken = localStorage.getItem(API_TOKEN_KEY);

    if (apiToken != null) {
      this.apiToken = apiToken;
    }
  }

  /**
   * Clears the JWT token and deletes it from the browsers `localStorage`. This basically means "logout".
   * We do not inform the backend since JWTs automatically expire after some time.
   */
  public clearAccessToken(): void {
    localStorage.removeItem(API_TOKEN_KEY);
    this.apiToken = "";
    this.router.navigateByUrl("/");
  }

  /**
   * Sets the JWT token (e.g. after successful login) and stores it in the browsers `localStorage`
   * @param _token {string} JWT token
   */
  public setAccessToken(_token: string) {
    this.apiToken = _token;
    localStorage.setItem(API_TOKEN_KEY, this.apiToken);
  }

  /**
   * Returns whether the client currently has a JWT token. This token must not be valid at the time, as
   * only the backend can validate.
   */
  public hasKey(): boolean {
    return this.apiToken !== "";
  }

  /**
   * Returns whether the current JWT token contains admin privileges.
   * If no JWT token is currently available, return always false.
   */
  public isAdmin() : boolean {
    if (this.hasKey()) {
      return decodeJWTToken(this.apiToken).admin;
    } else {
      return false;
    }
  }

  /**
   * Returns the current username stored in the JWT payload.
   * If no JWT token is currently available, return undefined.
   */
  public getUsername() : string | undefined {
    if (this.hasKey()) {
      return decodeJWTToken(this.apiToken).user;
    } else {
      return undefined;
    }
  }

  /**
   * Return the currently stored JWT token. Might be undefined if no JWT token is available.
   */
  public getAccessToken() {
    return this.apiToken;
  }

}