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 { SchoolData } from '../structures/school-data';

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

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

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

  // stav ukladani instruktoru propojenych s akci
  private schoolSaveStatus = new BehaviorSubject<number>(Globals.savingStatus.none);
  schoolSaveStatus$ = this.schoolSaveStatus.asObservable();

  constructor(private http: HttpClient) { }

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

  actualizeAllSchools(): void {
    this.http.get<SchoolData[]>(Globals.api.getAllSchools).pipe(catchError(this.handleError)).subscribe(data => {
        this.allSchools.next(data);
      }
    );
  }

  async getSchoolById(id: number): Promise<SchoolData | null> {
    // zkousim hledat mezi nactenymi
    if(this.allSchools.value != null) {
      var found = this.allSchools.value.find(school => school.ID == id)
      if(found != undefined) {
        var data = found;
        return new Promise(resolve => { resolve(data); });
      }
    }
    // musim kurz ziskat ze serveru
    var data = await this.http.get<SchoolData>(Globals.api.schoolGetById + '?schoolId=' + id).pipe( catchError(this.handleError)).toPromise();
    this.addLoadedSchool(data);
    return new Promise(resolve => { resolve(data); });
  }

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

  addLoadedSchool(newSchool: SchoolData): void {
    //newSchool = JSON.parse(JSON.stringify(newSchool));
    var copy = JSON.parse(JSON.stringify(newSchool));
    var schools = this.allSchools.value;
    if (schools != null) {
      schools.forEach(newSchool => {
        if(schools != null) {
          var index = schools.findIndex(school => { return school.ID == newSchool.ID; } );
          if(index == -1) {
            // kurz s timto ID jeste nebyl nacten, proto jej pridame
            schools.push(copy);
          } else {
            // kurz s timto ID je jiz nacten, proto jej pouze aktualizujeme
            schools.splice(index, 1)
            schools.push(copy);
          }
        } else {
          // nebyly jeste nacteny zadne kurzy, vkladame prvni
          schools = [newSchool];
        }
      }); 
    } else {
      schools = [newSchool];
    }
    //var copy = JSON.parse(JSON.stringify(schools));
    this.allSchools.next(schools);
  }

  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.');
  }
}
