import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, ReplaySubject } from 'rxjs';
import { environment } from '../../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/internal/operators';
import { Router } from '@angular/router';
import {StringHelper} from '../../helpers/string-helper';
import {LookupSourceService} from './lookup-source.service';

@Injectable()
export class SecurityService {

  public static auth: {
    accessToken: string,
    loggedIn: boolean
  };

  constructor(private http: HttpClient,
              private router: Router,
              private lookupService: LookupSourceService) {
  }

  private userObservable: BehaviorSubject<any>;
  private loggingOut = false;
  private administrator = false;
  private editorDatabase = false;

  public getUserInfo(): Observable<any> {

    if (!this.userObservable) {
      this.userObservable = new BehaviorSubject<any>({});

      if (!this.loggingOut) {
        this.queryServerUserInfo().subscribe((response: any) => {
          this.setAuth(response.accessToken);
          this.administrator = response.roleId === 1;
          this.editorDatabase = response.roleId === 1 || response.roleId === 2;
          this.userObservable.next(response);
        });
      }
    }

    return this.userObservable;
  }

  public invalidateCurrentUser() {
    this.userObservable = undefined;
    this.setAuth(null);
  }

  public isAdministrator(): boolean {
    return this.currentUserInfoLoaded() && this.administrator;
  }

  public isEditorDatabase(): boolean {
    return this.currentUserInfoLoaded() && this.editorDatabase;
  }

  public queryServerUserInfo(): Observable<any> {

    const qstring = environment.api + '/security/current-user-info';

    return this.http.get(qstring);
  }

  public getCurrentUserShortFio(): Observable<string> {
    return this.getUserInfo().pipe(map(userInfo => userInfo.lastName ? StringHelper.getPersonShortTitle(userInfo) : ''));
  }

  public getCurrentUserId(): Observable<number> {
    return this.getUserInfo().pipe(map(userInfo => userInfo.id));
  }

  public currentUserInfoLoaded(): boolean {
    return this.userObservable && this.userObservable.value && this.userObservable.value.id;
  }

  public loginByUsername(user: any) {
    const qstring = environment.api + '/security/login';
    return this.http.post(qstring, user)
      .pipe(map((response: any) => {
        this.invalidateCurrentUser();
        return response as any;
      }));
  }

  public setAuth(accessToken: string) {
    SecurityService.auth = {
      accessToken: accessToken ? accessToken : null,
      loggedIn: !!accessToken
    };
  }

  public loggedIn(): boolean {
    return SecurityService.auth && SecurityService.auth.loggedIn && !!this.currentUserInfoLoaded();
  }

  public logout() {

    this.getLogoutUrl()
      .subscribe(
        {
          next: (url: string) => {
            SecurityService.auth = null;
            this.invalidateCurrentUser();
          },
          error: error => {
            console.log(error);
            window.location.href = document.baseURI;
          }
        });
  }

  private getLogoutUrl(): Observable<string> {
    return this.http.get(`${environment.api}/security/logout`,
      { params: { 'redirectUri': document.baseURI } })
      .pipe(map((value: Response) => value.url));
  }

  public getListUsers(): Observable<any[]> {
    const qstring = environment.api + '/user/list-users';
    return this.http.get(qstring)
      .pipe(map((response: any) => {
        return response as any[];
      }));
  }

  public storeUser(user: any): Observable<any> {
    const qstring = environment.api + '/user/store';
    return this.http.post(qstring, user)
      .pipe(map((response: any) => {
        return response as any;
      }));
  }

  public deleteUser(user: any): Observable<any> {
    const qstring = environment.api + '/user/delete';
    return this.http.post(qstring, user)
      .pipe(map((response: any) => {
        return response;
      }));
  }
}
