import {Injectable, OnDestroy} from '@angular/core';
import {Subject} from "rxjs";
import {take, takeUntil, tap} from "rxjs/operators";
import {AppState} from "../../shared/app-state";
import {HttpClient, HttpResponse} from "@angular/common/http";
import {environment} from "../../../../environments/environment";
import {ApiService} from "../../shared/service/api.service";
import {Employee, EmployeePermission} from "../../shared/model/employee";

@Injectable({
  providedIn: 'root'
})
export class AccountService implements OnDestroy {
  private destroy$ = new Subject<boolean>()

  constructor(
    private http: HttpClient,
    private api: ApiService,
    private appState: AppState
  ) {
  }

  ngOnDestroy(): void {
    this.destroy$.next(true)
    this.destroy$.complete()
  }

  isLoggedIn(): boolean {
    return this.appState.isAuthenticated
  }

  checkAuthenticationStatus() {
    if (!this.appState.authenticatedEmployee) {
      // Try to get current default group user
      this.http.get<Employee>(`${environment.apiUrl}/employee/current`, {withCredentials: true})
        .pipe(
          take(1),
          takeUntil(this.destroy$),
        ).subscribe({
        next: employee => this.appState.authenticatedEmployee = employee,
        error: err => {
          if (err.status === 404) {
            console.error('No default user is defined on this computer')
          } else {
            console.error('An error occurred while authenticating the default user')
            console.error(err)
          }
        }
      })
    }
  }

  login(id: number, password: string, success: () => void, error: (err) => void) {
    const loginForm = {id, password}
    this.http.post<any>(`${environment.apiUrl}/login`, loginForm, {
      withCredentials: true,
      observe: 'response' as 'body'
    })
      .pipe(
        take(1),
        takeUntil(this.destroy$)
      )
      .subscribe({
        next: (response: HttpResponse<any>) => {
          this.appState.authenticationExpiration = parseInt(response.headers.get("X-Authentication-Expiration"))
          this.appState.isAuthenticated = true
          this.setLoggedInEmployeeFromApi()
          success()
        },
        error: err => error(err)
      })
  }

  logout(success: () => void) {
    this.api.get<void>('/employee/logout', true).pipe(
      take(1),
      takeUntil(this.destroy$)
    )
      .subscribe({
        next: () => {
          this.appState.isAuthenticated = false
          this.appState.authenticationExpiration = -1
          this.appState.authenticatedEmployee = null
          this.checkAuthenticationStatus()
          success()
        },
        error: err => console.error(err)
      })
  }

  hasPermission(permission: EmployeePermission): boolean {
    return this.appState.authenticatedEmployee.permissions.indexOf(permission) >= 0
  }

  private setLoggedInEmployeeFromApi() {
    this.api.get<Employee>("/employee/current", true)
      .pipe(
        take(1),
        takeUntil(this.destroy$)
      )
      .subscribe({
        next: employee => this.appState.authenticatedEmployee = employee,
        error: err => {
          console.error("Could not get the logged in employee from the API: ")
          console.error(err)
        }
      })
  }
}
