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

import { LoginService } from './login.service';

import { InstructorData } from '../structures/instructor-data';

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

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

  // data o vsech instruktorech v aplikaci
  private allInstructors = new BehaviorSubject<InstructorData[] | null>(null);
  allInstructors$ = this.allInstructors.asObservable();

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

  // stav ukladani uzivatelske role instruktora
  private instructorRoleSaveStatus = new BehaviorSubject<number>(Globals.savingStatus.none);
  instructorRoleSaveStatus$ = this.instructorRoleSaveStatus.asObservable();

  constructor(private http: HttpClient, private loginService: LoginService, private snackBar: MatSnackBar) { }

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

  async getInstructorById(id: number): Promise<InstructorData | null> {
    if(this.allInstructors.value == null) {
      var data = await this.http.get<InstructorData[]>(Globals.api.getAllInstructors).pipe( catchError(this.handleError)).toPromise();
      this.allInstructors.next(data);
    }
    if(this.allInstructors.value != null) {
      var found = this.allInstructors.value.find(instructor => instructor.ID == id)
      if(found != undefined) {
        var userData = found;
        return new Promise(resolve => { resolve(userData); });
      }
    }
    return new Promise(resolve => { resolve(null); });
  }

  actualizeAllInstructors(): void {
    this.http.get<InstructorData[]>(Globals.api.getAllInstructors).pipe( catchError(this.handleError)).subscribe(
      data => this.allInstructors.next(data)
    );
  }

  async changeInstructorRole(id: number, newRole: string): Promise<void> {
    this.instructorRoleSaveStatus.next(Globals.savingStatus.inProgress);
    var index = this.allInstructors.value?.findIndex(instructor => instructor.ID == id);
    if(this.allInstructors.value != null && index != undefined && index != -1) {
      this.allInstructors.value[index].role = newRole;
      var data = { ID: this.allInstructors.value[index].ID, role: newRole };
      await this.http.post<any>(Globals.api.changeInstructorRole, data, Globals.httpOptions).pipe( catchError(this.handleError)).toPromise().then(
        (val) => {
          this.allInstructors.next(this.allInstructors.value),
          this.instructorRoleSaveStatus.next(Globals.savingStatus.success)
        },
        (err) => this.instructorRoleSaveStatus.next(Globals.savingStatus.failed)
      );
    }
    //return true;
  }

  async saveInstructorData(data: InstructorData): Promise<void> {
    this.instructorSaveStatus.next(Globals.savingStatus.inProgress);
    // ulozeni jako aktualni uzivatel
    if(data.ID == this.loginService.getActualUserData()?.instructor?.ID){
      var actualData = this.loginService.getActualUserData();
      if(actualData != null) {
        actualData.instructor = data;
        this.loginService.changeUserData(actualData);
      }
    }
    // ulozeni do seznamu vsech instruktoru
    var index = this.allInstructors.value?.findIndex(instructor => instructor.ID == data.ID);
    if(this.allInstructors.value != null && index != undefined && index != -1) {
      this.allInstructors.value[index] = data;
    }
    // odeslani do databaze
    await this.http.post<InstructorData[]>(Globals.api.saveInstructorProfile, data, Globals.httpOptions).pipe( catchError(this.handleError)).toPromise().then(
      (val) => this.instructorSaveStatus.next(Globals.savingStatus.success),
      (err) => this.instructorSaveStatus.next(Globals.savingStatus.failed)
    );
    //this.actualizeAllInstructors();
    //return new Promise(resolve => { resolve(null); });
  }

  // pro pouziti pri odhlaseni
  clearAll(): void {
    this.allInstructors.next(null);
  }

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