import {BehaviorSubject, from, Observable, Subscription, throwError as observableThrowError} from 'rxjs';
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {catchError, map} from "rxjs/operators";
import {properties} from "../../../../../environments/environment";

@Injectable({  providedIn: 'root' })
export class ContextsService {
  private communitiesSubject: BehaviorSubject<any> = new BehaviorSubject(null);
  private promise: Promise<void>;
  private sub: Subscription = null;

  constructor(private http: HttpClient=null ) {
  }

  ngOnDestroy() {
    if(this.sub) {
      this.sub.unsubscribe();
    }
  }

  public getCommunities( apiUrl:string):any {
  let  url   = apiUrl + 's/';
      return this.http.get(url)
                    .pipe(map(res => this.parseCommunities(res, true) ))
                    // .do(request => console.info("Get claims: offset = "))
                    .pipe(catchError(this.handleError));
  }
  public getPublicCommunities( apiUrl:string):any {
    let  url   = apiUrl + 's/';
    return this.http.get(url)
      .pipe(map(res => this.parseCommunities(res, false) ));
  }

  public initCommunities() {
    let url = properties.contextsAPI + 's/';
    this.promise = new Promise<void>((resolve => {
      this.sub = this.http.get((properties.useLongCache) ? (properties.cacheUrl + encodeURIComponent(url)) : url)
        .pipe(map(res => this.parseCommunities(res, true) ))
        .subscribe(
          (communties) => {
            this.communitiesSubject.next(communties);
            resolve();
          },
          error => {
            this.communitiesSubject.error(error);
            resolve();
          });
    }));

  }

  async getCommunitiesByStateAsync(getAll: boolean) {
    if(!this.promise) {
      this.initCommunities();
    }

    await this.promise;
    if(this.sub){
      this.sub.unsubscribe();
    }
    if(getAll) {
      return this.communitiesSubject.getValue();
    } else {
      return this.communitiesSubject.getValue().filter(community => community.status != 'hidden');
    }
  }

  getPublicCommunitiesByState(): Observable<any> {
    return from(this.getCommunitiesByStateAsync(false));
  }

  getCommunitiesByState(): Observable<any> {
    return from(this.getCommunitiesByStateAsync(true));
  }

  parseCommunities(data, getall){
    var communities = [];

    for(var i = 0; i< data.length; i++){
      if(data[i].type && (data[i].type == "ri" || data[i].type == "community")){
        if(getall || data[i].status!='hidden') {
          communities.push(data[i]);
        }
      }
    }
    return communities;
  }
  public getCategories(communityId :string, apiUrl:string):any {
    //console.info('ContextsService:  request categories for community  with id '+communityId);
    let url= apiUrl  + '/' + communityId ;
      return this.http.get(url)
                    //.map(request => <any> request.json())
                    // .do(request => console.info("Get claims: offset = " ))
                    .pipe(catchError(this.handleError));
  }
  public getConcepts(categoryId :string, keyword: string, parsing:boolean, apiUrl:string):any {
    //console.info('ContextsService:  request concept for category  with id '+categoryId + ' and keyword '+ keyword);
    let url= apiUrl  + '/category/' + categoryId;


      return this.http.get(url )
                    .pipe(catchError(this.handleError))
                    .pipe(map(res => (parsing)?this.parse(res):res));
  }
  public getSubConcepts(subConceptID :string, keyword: string, parsing:boolean, apiUrl:string):any {
    //console.info('ContextsService:  request subscriptions concept for concept with id '+subConceptID + ' and keyword '+ keyword);
    let url= apiUrl  + '/category/concept/' + subConceptID;
    let key = url+"_parsing="+parsing;


      return this.http.get(url )
                    .pipe(catchError(this.handleError))
                    .pipe(map(res => (parsing)?this.parseSubConcepts(res):res));
  }
  parse (data: any):any {
      var array =[]
      if(!Array.isArray(data) && data.id && data.label){
        var value ={id:"",label:"",hasSubConcept:""};
        value.id = data.id;
        value.label = data.label;
        value.hasSubConcept = data.hasSubConcept;
        array.push(value);
      }
      for(var i = 0; i < data.length; i++){
        var value={id:"",label:"",hasSubConcept:""};
        value.id = data[i].id;
        value.label = data[i].label;
        value.hasSubConcept = data[i].hasSubConcept;
        array.push(value);
      }

      return array;

  }
  parseSubConcepts (data: any):any {
      var array = []
      if(data.length >0 && data[0].concepts){
        var concepts = data[0].concepts;
        for(var i = 0; i < concepts.length; i++){
          var value ={id:"",label:"",hasSubConcept:""};
          value.id = concepts[i].id;
          value.label = concepts[i].label;
          value.hasSubConcept = concepts[i].hasSubConcept;
          if(concepts[i].concepts){
            var subconcepts = concepts[i].concepts;
            for(var x = 0; x < subconcepts.length; x++){
              var value ={id:"",label:"",hasSubConcept:""};
              value.id = subconcepts[x].id;
              value.label = subconcepts[x].label;
              value.hasSubConcept = subconcepts[x].hasSubConcept;
              array.push(value);
            }
          }
          array.push(value);
        }
    }
      return array;

  }

  private handleError (error: any) {
    // in a real world app, we may send the error to some remote logging infrastructure
    // instead of just logging it to the console
    console.log(error);
    return observableThrowError(error  || 'Server error');
  }
}
