import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
import { AuthService } from '@core/auth';
import { ScanAdapterService } from '@adapter/scan';
import { AuthService as IsaAuthService } from '@generated/swagger/isa-api';
import { UiConfirmModalComponent, UiErrorModalComponent, UiModalResult, UiModalService } from '@ui/modal';
import { EnvironmentService } from '@core/environment';
import { injectNetworkStatus$ } from '../services/network-status.service';
import { toSignal } from '@angular/core/rxjs-interop';

@Injectable({ providedIn: 'root' })
export class IsAuthenticatedGuard {
  constructor(
    private _router: Router,
    private _authService: AuthService,
    private _scanService: ScanAdapterService,
    private _isaAuthService: IsaAuthService,
    private _modal: UiModalService,
    private _environmentService: EnvironmentService,
  ) {}

  networkStatus = toSignal(injectNetworkStatus$());

  async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    const authenticated = await this._authService.isAuthenticated();

    if (!authenticated) {
      const token = await this.scanAndGetToken();

      if (token) {
        this._authService.setKeyCardToken(token);
      }
      this._authService.login();
    }

    return authenticated;
  }

  async scanAndGetToken(): Promise<string> {
    if (this._environmentService.isDesktop()) {
      return undefined;
    }

    let loginModalResult: UiModalResult<any>;

    do {
      const loginModal = this._modal.open({
        content: UiConfirmModalComponent,
        title: 'Anmeldung',
        data: {
          message: 'Bitte wählen Sie die Anmeldeoption aus.',
          rejectLabel: 'Anmeldung mit Logindaten',
          confirmLabel: 'Anmeldung mit Keycard',
        },
      });

      loginModalResult = await loginModal.afterClosed$.toPromise();
    } while (this.networkStatus() === 'offline');

    if (!loginModalResult.data) {
      return undefined;
    }

    const result = await this._scanService.scan()?.toPromise();

    if (typeof result === 'string') {
      try {
        const res = await this._isaAuthService
          .AuthLogin({
            code: result,
            application: 'isa',
            hostname: location.host,
          })
          .toPromise();

        return res.token;
      } catch (error) {
        const errorModalRef = this._modal.open({
          content: UiErrorModalComponent,
          title: 'Fehler bei der Anmeldung',
          data: {
            message: 'Versuchen Sie es erneut\noder melden Sie sich mit\nIhren Benutzerdaten an.',
          },
        });

        await errorModalRef.afterClosed$.toPromise();

        return this.scanAndGetToken();
      }
    }

    return undefined;
  }
}
