import { Injectable, isDevMode } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {LocalStorageService} from 'angular-2-local-storage';
import {Observable} from 'rxjs';
import {ErrorComponent} from '../error/error.component';
import {ModalService} from '@inst-iot/bosch-angular-ui-components';


@Injectable({
  providedIn: 'root'
})
export class ApiService {

  private host = isDevMode() ? '/api' : 'https://definma-api.apps.de1.bosch-iot-cloud.com';

  constructor(
    private http: HttpClient,
    private storage: LocalStorageService,
    private modalService: ModalService,
    private window: Window
  ) { }

  get hostName() {
    return this.host;
  }

  // main HTTP methods
  get<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
    this.requestErrorHandler<T>(this.http.get(this.url(url), this.options()), f);
  }

  post<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
    this.requestErrorHandler<T>(this.http.post(this.url(url), data, this.options()), f);
  }

  put<T>(url, data = null, f: (data?: T, err?, headers?) => void = () => {}) {
    this.requestErrorHandler<T>(this.http.put(this.url(url), data, this.options()), f);
  }

  delete<T>(url, f: (data?: T, err?, headers?) => void = () => {}) {
    this.requestErrorHandler<T>(this.http.delete(this.url(url), this.options()), f);
  }

  // execute request and handle errors
  private requestErrorHandler<T>(observable: Observable<any>, f: (data?: T, err?, headers?) => void) {
    observable.subscribe(data => {  // successful request
      f(
        data.body,
        undefined,
        data.headers.keys().reduce((s, e) => {s[e.toLowerCase()] = data.headers.get(e); return s; }, {})
      );
    }, err => {  // error
      if (f.length > 1) {  // pass on error
        f(undefined, err, undefined);
      }
      else {  // handle directly
        this.requestError(err);
      }
    });
  }

  requestError(err) {  // network error dialog
    const modalRef = this.modalService.openComponent(ErrorComponent);
    modalRef.instance.message = 'Network request failed!';
    const details = [err.error.status];
    if (err.error.details) {
      details.push(err.error.details);
    }
    modalRef.instance.details = details;
    modalRef.result.then(() => {
      this.window.location.reload();
    });
  }

  private url(url) {  // detect if host was given, otherwise use default host
    if (/http[s]?:\/\//.test(url)) {
      return url;
    }
    else {
      return this.host + url;
    }
  }

  // generate request options
  private options(): {headers: HttpHeaders, observe: 'body'} {
    return {headers: this.authOptions(), observe: 'response' as 'body'};
  }

  // generate Basic Auth
  private authOptions(): HttpHeaders {
    const auth = this.storage.get('basicAuth');
    if (auth) {
      return new HttpHeaders({Authorization: 'Basic ' + auth});
    }
    else {
      return new HttpHeaders();
    }
  }
}
