import {Injectable} from "@angular/core";
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot} from "@angular/router";
import {Observable} from "rxjs";
import {HttpClient, HttpParams} from "@angular/common/http";
import {MessagesService, ProgressIndicationService} from "@webbpm/base-package";
import {AuthenticationService} from "../authentication.service";
import {EsiaErrorDetail} from "../EsiaErrorDetail";

@Injectable({providedIn:'root'})
export abstract class AuthGuard implements CanActivate {

  protected constructor(
      protected router: Router,
      private httpClient: HttpClient,
      private authenticationService: AuthenticationService,
      private progressIndicationService: ProgressIndicationService,
      private messageService: MessagesService
  ) {
  }

  public canActivate(route: ActivatedRouteSnapshot,
                     state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    let hasAccess: Promise<boolean> | boolean = this.checkAccess();

    return Promise.resolve(hasAccess).then((isAccess) => {
      let url = new URL(window.location.href);
      let params = new URLSearchParams(url.search);
      let code = params.get('code');
      let state = params.get('state');
      let error = params.get('error');
      let errorDescription = params.get('error_description');
      if (code || state || error || errorDescription) {
        window.history.replaceState({}, document.title, url.pathname);
      }
      if (isAccess) {
        return true;
      }
      if (error) {
        let errorMessage =
            this.messageService.getUnknowErrorMessage();
        let errorCode = this.extractCode(errorDescription);
        if (errorCode) {
          errorMessage = EsiaErrorDetail.getDescription(errorCode);
        }
        let consoleError = error + ', error description = ' + errorDescription;
        this.messageService.error(errorMessage);
        console.error(consoleError);
        return false;
      }
      if (code && state) {
        this.progressIndicationService.showProgressBar();
        const params = new HttpParams().set('code', code).set('state', state);
        this.httpClient.get("esia/auth",
                            {
                              params: params,
                              responseType: 'text',
                              observe: 'response',
                              headers: {
                                "Error-intercept-skip":"true"
                              }
                            })
            .toPromise()
            .then(
                () => {
                  this.progressIndicationService.hideProgressBar();
                  window.open(url.origin + url.pathname, "_self");
                })
            .catch(reason => {
              const json = JSON.parse(reason.error);
              json.messages.forEach((errorMessage) => {
                this.messageService.error(errorMessage, json);
              })
            })
            .finally(() => this.progressIndicationService.hideProgressBar());
        return false;
      }
      else {
        return this.authenticationService.redirectToEsia().toPromise().catch((reason) => {
          console.error(reason);
          return false;
        });
      }
    }).catch((reason) => {
      console.error(reason);
      return false
    });
  }

  private checkAccess(): boolean {
    return this.authenticationService.isAuthenticated();
  }

  private extractCode(message: string): string | null {
    const regex = /ESIA-\d{6}/;
    const match = message.match(regex);
    return match ? match[0] : null;
  }
}
