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} 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 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 error = params.get('error');
      let errorDescription = params.get('error_description');
      if (isAccess) {
        return true;
      }
      else if (error) {
        let userErrorMessage = 'Произошла неизвестная ошибка. Обратитесь к системному администратору';
        let errorCode = this.extractCode(errorDescription);
        if (errorCode) {
          userErrorMessage = EsiaErrorDetail.getDescription(errorCode);
        }
        let errorMessage = error + ', error description = ' + errorDescription;
        this.messageService.error(userErrorMessage)
        throw new Error(errorMessage);
      }
      else if (code) {
        const params = new HttpParams().set('code', code);
        this.httpClient.get("esia/auth",
                            {
                              params: params, responseType: 'text', observe: 'response', headers: {
                                "Error-intercept-skip": "true"
                              }
                            })
            .toPromise()
            .then(
                (response) => {
                  window.open(url.origin + url.pathname, "_self");
                })
            .catch((reason) => {
              let errorMessage = reason.error.messages != null
                                 ? reason.error.messages
                                 : reason.error.replaceAll('\\', '');
              this.messageService.error(errorMessage);
              console.error(reason);
            });
        return false;
      }
      else {
        this.httpClient.get<string>("esia/url")
            .toPromise()
            .then(url => window.open(url, "_self"));
        return true;
      }
    }).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;
  }
}
