import { HttpErrorResponse } from '@angular/common/http';
import { Injectable, Renderer2, RendererFactory2 } from '@angular/core';
import {
  AccountDto,
  AccountResDto,
  EditPasswordDto,
  LinkVerificationDto,
  RecoveryDto,
} from '@api/models';
import { AuthApiClient } from '@api/services/auth-api-client';
import {
  BehaviorSubject,
  catchError,
  distinctUntilChanged,
  ReplaySubject,
  shareReplay,
  tap,
  throwError,
} from 'rxjs';
import { JwtService } from './jwt.service';

@Injectable({ providedIn: 'root' })
export class AuthService {
  private currentUserSubject = new BehaviorSubject<AccountResDto | null>(null);
  public currentUser = this.currentUserSubject
    .asObservable()
    .pipe(distinctUntilChanged(), shareReplay(1));

  private isAuthenticatedSubject = new ReplaySubject<boolean>(1);
  public isAuthenticated$ = this.isAuthenticatedSubject.asObservable();
  private renderer: Renderer2;

  constructor(
    private jwtService: JwtService,
    private rendererFactory: RendererFactory2,
    private authApiClient: AuthApiClient,
  ) {
    this.renderer = this.rendererFactory.createRenderer(null, null);
  }

  populate() {
    const token = this.jwtService.getToken();
    if (!token) {
      this.purgeAuth();
      return;
    }
    return this.authApiClient.authControllerMe({}).pipe(
      tap((account) => this.setAuth(account)),
      catchError((err: HttpErrorResponse) => {
        this.purgeAuth();
        return throwError(() => err);
      }),
    );
  }

  get userAccountFullName() {
    const account = this.getCurrentUser();
    const fullName = account ? `${account.firstName} ${account.lastName}` : '';
    return fullName;
  }

  setAuth(user: AccountResDto) {
    this.jwtService.saveToken(user.token);
    this.currentUserSubject.next(user);
    this.isAuthenticatedSubject.next(true);
    /* rimuove lo splashscreen all'avvio in index.html */
    // let loader = this.renderer.selectRootElement('#splash-screen');
    // this.renderer.setStyle(loader, 'display', 'none');
  }

  purgeAuth() {
    this.jwtService.destroyToken();
    this.currentUserSubject.next(null);
    this.isAuthenticatedSubject.next(false);
  }

  attemptAuth(credentials: AccountDto) {
    return this.authApiClient
      .authControllerLogin({ body: credentials })
      .pipe(tap((account) => this.setAuth(account)));
  }

  recoverPassword(body: RecoveryDto) {
    return this.authApiClient.authControllerRecoveryPassword({ body }).pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(() => err);
      }),
    );
  }

  linkVerification(body: LinkVerificationDto) {
    return this.authApiClient.authControllerLinkVerification({ body }).pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(() => err);
      }),
    );
  }

  setPassword(body: EditPasswordDto) {
    return this.authApiClient.authControllerSetPassword({ body }).pipe(
      catchError((err: HttpErrorResponse) => {
        return throwError(() => err);
      }),
    );
  }

  getCurrentUser(): AccountResDto | null {
    return this.currentUserSubject.getValue();
  }
}
