import {Injectable} from "@angular/core";
import {Observable, ReplaySubject} from "rxjs";
import {v4 as uuidv4} from 'uuid';
import {JwtHelperService} from "@auth0/angular-jwt";
import * as _ from 'underscore';
import {ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot, UrlTree} from "@angular/router";
import {map} from "rxjs/operators";
import {InjectableRxStompConfig, RxStompService} from "@stomp/ng2-stompjs";
import {myRxStompConfig} from "../stomp.config";
import {HttpClient} from "@angular/common/http";

@Injectable({providedIn: "root"})
export class PersonService implements CanActivate, CanActivateChild {

  private siteId: string
  private helper = new JwtHelperService();
  private currentPerson: Observable<Person>

  constructor(private rxStompService: RxStompService, private httpClient: HttpClient) {
    if (!(this.siteId = localStorage.siteId)) {
      localStorage.siteId = this.siteId = uuidv4()
    }
    let tk = this.getCurrentToken()
    if (tk != null) {
      this.startStomp(tk);
    }
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.getCurrentPerson().pipe(map(person => _.isObject(person.auth)))
  }

  canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.canActivate(childRoute, state)
  }

  resetCurrentPerson() {
    localStorage.removeItem("token");
    this.currentPerson = null;
  }

  startStomp(token: any) {
    const config: InjectableRxStompConfig = {...myRxStompConfig, connectHeaders: {"login": token.sub, "passcode": token.rawToken}};
    this.rxStompService.configure(config);
    this.rxStompService.activate();
  }

  setCurrentPerson(token: string) {
    this.resetCurrentPerson();
    localStorage.setItem("token", token);
    let tk = this.getCurrentToken()
    this.startStomp(tk);
  }

  getCurrentToken(): any {
    let tkr = localStorage.getItem("token");
    if (!_.isEmpty(tkr)) {
      let decodedToken = this.helper.decodeToken(tkr);
      decodedToken.rawToken = tkr
      if (!this.helper.isTokenExpired(tkr)) {
        return decodedToken
      } else {
        this.resetCurrentPerson()
      }
    }
    return null
  }

  getCurrentPerson(): Observable<Person> {
    if (this.currentPerson == null) {
      let ret = this.currentPerson = new ReplaySubject<Person>();
      setTimeout(() => {
        let p = new Person();
        p.siteId = this.siteId
        let tk = this.getCurrentToken();
        if (tk != null) {
          p.auth = <PersonInfo>{id: tk.sub};
        }
        ret.next(p)
      }, 100)
    }
    return this.currentPerson;
  }

  getFirstRunInfo(): Observable<PersonFirstRun> {
    let ret = new ReplaySubject<PersonFirstRun>();
    this.getCurrentPerson().subscribe(person => this.httpClient.get(`/api/old/person/${person.auth.id}/first-run`).pipe(map((r: any) => <PersonFirstRun>r)).subscribe(fr => ret.next(fr)))
    return ret;
  }

  getSiteId(): string {
    return this.siteId
  }
}

export class Person {
  public siteId: string
  public auth: PersonInfo
}

export class PersonInfo {
  id: string
}

export class PersonFirstRun {
  firstRun: boolean
  codes: string[]
}
