import {
  BaseComponent, ControlWithValue,
  Filter,
  Filterable,
  FilterComponent,
  NotNull, ObjectRef,
  Visible
} from "@webbpm/base-package";
import {of, Subject} from "rxjs";
import {debounceTime, filter, switchMap, takeUntil} from "rxjs/operators";

export class FilterGroupDelegate extends BaseComponent {
  @NotNull()
  @ObjectRef()
  public filterComponents: FilterComponent[];

  @NotNull()
  public liveFilter: boolean = false;

  @NotNull()
  public triggerOnStart: boolean = false;

  private filterable: Filterable;

  private loadSubject: Subject<any> = new Subject<any>();
  private onFilterChange = () => this.triggerFilter();

  initialize() {
    super.initialize();

    this.loadSubject.pipe(
        debounceTime(400),
        filter(x => !!x),
        switchMap(filters => of(filters).pipe(
            takeUntil(this.loadSubject)
        ))
    ).subscribe(filters => {
      this.reloadFilterable(filters);
    });

    this.filterable = this.getScript('common.Filterable')
  }

  postStart() {
    super.postStart();
    if (this.liveFilter) {
      this.registerLiveFiltering();
    }

    if (this.triggerOnStart) {
      this.triggerFilter();
    }
  }

  @Visible()
  public triggerFilter(): void {
    let filters = this.filterComponents
        .map(filter => filter.getFilter())
        .filter(filterModel => filterModel != null);

    this.filterComponents
        .filter(filter => filter.getFilter() == null)
        .forEach(filter => this.filterable.removeFilter(filter.getObjectId()));

    return this.reload(filters);
  }

  public setLiveFilter(liveFilter: boolean): void {
    if (this.liveFilter === liveFilter) {
      return;
    }

    this.liveFilter = liveFilter;
    if (this.liveFilter) {
      this.registerLiveFiltering();
    }
    else {
      this.unregisterLiveFiltering();
    }
  }

  protected reload(filters: Filter[]) {
    this.loadSubject.next(filters);
  }

  protected reloadFilterable(filters: Filter[]) {
    this.filterable.reload(filters);
  }

  protected registerLiveFiltering() {
    this.filterComponents.forEach(filterComponent => {
      let controlWithValue: ControlWithValue = filterComponent.getFilterInputControl();
      if (controlWithValue) {
        controlWithValue.addChangeListener(this.onFilterChange);
      }
    });
  }

  protected unregisterLiveFiltering() {
    this.filterComponents.forEach(filterComponent => {
      let controlWithValue: ControlWithValue = filterComponent.getFilterInputControl();
      if (controlWithValue) {
        controlWithValue.removeChangeListener(this.onFilterChange);
      }
    });
  }
}