/*
 * Copyright (C) 2019 Robert Bosch GmbH Copyright (C) 2019 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Injectable } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import { first } from 'rxjs/operators';

import { ModalWindowService } from '../modal-window/modal-window.service';
import { LoadingScreenComponent } from './loading-screen.component';
import { LoadingScreenOptions } from './loading-screen.model';
import { BehaviorSubject, Subject } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class LoadingScreenService {
  private dialogRef: MatDialogRef<LoadingScreenComponent>;

  /**
   * Signals when loading screen is closed.
   */
  public closed: Subject<boolean>;

  /**
   * Signals when loading screen is opened.
   */
  public opened: Subject<boolean>;

  /**
   * Observable to provide the value (in percentage) of the progress bar.
   */
  public value = new BehaviorSubject<number>(undefined);

  /**
   * Observable to provide the status text of the progress bar.
   */
  public status = new BehaviorSubject<string>(undefined);

  constructor(private modalWindowService: ModalWindowService) {
    this.opened = new Subject<boolean>();
    this.closed = new Subject<boolean>();
  }

  /**
   * Shows the loading screen dialog using given options
   * @param options The options to apply to the loading screen dialog.
   */
  show(options?: LoadingScreenOptions) {
    options = options || {};
    this.dialogRef = this.modalWindowService.openDialogWithComponent(LoadingScreenComponent, {
      data: options,
      width: options.dialogScreenWidth || '896px',
    });

    // need to set disable close here instead of dialog options since modalWindowService is overriding the value
    if (options.closeable !== undefined) {
      this.dialogRef.disableClose = !options.closeable;
    } else {
      this.dialogRef.disableClose = true;
    }

    this.dialogRef
      .afterOpened()
      .pipe(first())
      .subscribe(() => {
        this.opened.next(true);
        this.closed.next(false);
        this.value.next(options.initialValue);
        this.status.next(options.initialStatus);
      });

    this.dialogRef
      .afterClosed()
      .pipe(first())
      .subscribe(() => {
        this.opened.next(false);
        this.closed.next(true);
        this.value.next(undefined);
        this.status.next(undefined);
      });
  }

  /**
   * Closes the loading screen dialog
   */
  close() {
    this.dialogRef.close();
  }

  /**
   * Shows the loading screen given progress value and status
   * @param value The progress bar value in percentage. If not given then next value of the progress bar is set automatically.
   * @param status The status text to show below the progress bar. If not given then old status is preserved.
   */
  progress(value?: number, status?: string) {
    if (!this.dialogRef.componentInstance) {
      return;
    }
    if (value) {
      // if value is specified then set the percentage value
      this.dialogRef.componentInstance.valuePercent = value;
    } else {
      // if value is not specified then increase by 1 the old percentage value
      value = (this.dialogRef.componentInstance.valuePercent || 0) + 1;
      this.dialogRef.componentInstance.valuePercent = value;
    }

    this.value.next(value);

    // if status is given then update the status text
    if (status) {
      this.setStatus(status);
    }
  }

  /**
   * Updates the loading screen status text
   * @param status The status text to show below the progress bar. If not given or empty then status will be hidden.
   */
  setStatus(status?: string) {
    if (!this.dialogRef.componentInstance) {
      return;
    }
    this.dialogRef.componentInstance.statusText = status;
    this.status.next(status);
  }
}
