import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

import { CourseThemeData } from '../structures/course-theme-data';

import * as Globals from '../globals';

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

  private courseThemes = new BehaviorSubject<CourseThemeData[] | null>(null);
  courseThemes$ = this.courseThemes.asObservable();

  // stav ukladani informaci o tematu kurzu
  private courseThemeSaveStatus = new BehaviorSubject<number>(Globals.savingStatus.none);
  courseThemeSaveStatus$ = this.courseThemeSaveStatus.asObservable();

  constructor(private http: HttpClient) { }

  saveStatusReset(): void {
    if(this.courseThemeSaveStatus.value != Globals.savingStatus.inProgress) {
      this.courseThemeSaveStatus.next(Globals.savingStatus.none);
    }
  }

  actualizeCourseThemes(): void {
    this.http.get<CourseThemeData[]>(Globals.api.getCourseThemes).pipe(catchError(this.handleError)).subscribe(data => {
        this.courseThemes.next(data);
      }
    );
  }

  async saveCourseThemeData(data: CourseThemeData): Promise<CourseThemeData | null> {
    var result = null;
    this.courseThemeSaveStatus.next(Globals.savingStatus.inProgress);
    if(data.ID == 0) {
      // vytvoreni noveho kurzu
      await this.http.post<CourseThemeData>(Globals.api.createTheme, data, Globals.httpOptions).pipe( catchError(this.handleError)).toPromise().then(
        (val) => {
          this.addLoadedCourseTheme(val),
          this.courseThemeSaveStatus.next(Globals.savingStatus.success),
          result = val
        },
        (err) => this.courseThemeSaveStatus.next(Globals.savingStatus.failed)
      );
    } else {
      // ulozeni zmen
      await this.http.post<CourseThemeData>(Globals.api.updateTheme, data, Globals.httpOptions).pipe( catchError(this.handleError)).toPromise().then(
        (val) => {
          this.addLoadedCourseTheme(val),
          this.courseThemeSaveStatus.next(Globals.savingStatus.success),
          result = val
        },
        (err) => this.courseThemeSaveStatus.next(Globals.savingStatus.failed)
      );
    }
    return result;
  }

  addLoadedCourseTheme(newTheme: CourseThemeData): void {
    var allThemes = this.courseThemes.value;
    if(allThemes != null) {
      var index = allThemes.findIndex(course => { return course.ID == newTheme.ID; } );
      if(index == -1) {
        // kurz s timto ID jeste nebyl nacten, proto jej pridame
        allThemes.push(newTheme);
      } else {
        // kurz s timto ID je jiz nacten, proto jej pouze aktualizujeme
        allThemes[index] = newTheme;
      }
    } else {
      // nebyly jeste nacteny zadne kurzy, vkladame prvni
      allThemes = [newTheme];
    }
    this.courseThemes.next(allThemes);
  }

  async getThemeById(id: number): Promise<CourseThemeData | null> {
    // zkousim hledat mezi mymi kurzy
    if(this.courseThemes.value != null) {
      var found = this.courseThemes.value.find(theme => theme.ID == id)
      if(found != undefined) {
        var themeData = found;
        return new Promise(resolve => { resolve(themeData); });
      }
    }
    // musim kurz ziskat ze serveru
    var themeData = await this.http.get<CourseThemeData>(Globals.api.themeGetById + '?themeId=' + id).pipe( catchError(this.handleError)).toPromise();
    return new Promise(resolve => { resolve(themeData); });
  }

  private handleError(error: HttpErrorResponse) {
    if (error.error instanceof ErrorEvent) {
      // A client-side or network error occurred. Handle it accordingly.
      console.error('An error occurred:', error.error.message);
    } else {
      // The backend returned an unsuccessful response code.
      // The response body may contain clues as to what went wrong.
      console.error(
        `Backend returned code ${error.status}, ` +
        `body was: ${error.error}`);
    }
    // Return an observable with a user-facing error message.
    return throwError(
      'Something bad happened; please try again later.');
  }
}
