import { Component, ChangeDetectionStrategy, OnInit, ViewChild, ElementRef, OnDestroy, Renderer2, ChangeDetectorRef } from '@angular/core';
import { IsaOverlayRef } from 'apps/sales/src/app/core/overlay/isa-overlay-ref';
import { Select } from '@ngxs/store';
import { RemissionSelectors } from 'apps/sales/src/app/core/store/selectors/remission.selectors';
import { Observable, BehaviorSubject, interval } from 'rxjs';
import { RemissionProcess, RemissionSelectedFilters, RemissionService, CapacityType } from '@isa/remission';
import { RemissionFilterService } from '../../services/remission-filter.service';
import { Filter, SelectFilter, SelectFilterOption } from '../../../filter';
import { RemissionResourceType } from '../../models/remission-resource-type.model';
import { withLatestFrom, filter, switchMap, map, throttleTime, startWith } from 'rxjs/operators';
import { isNullOrUndefined } from 'util';
import { slideIn } from 'apps/sales/src/app/core/overlay';

@Component({
  selector: 'app-remission-list-filter',
  templateUrl: 'remission-list-filter.component.html',
  styleUrls: ['remission-list-filter.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: [slideIn],
})
export class RemissionListFilterComponent implements OnInit, OnDestroy {
  animate: 'in' | 'out' = 'in';
  inTransition = true;

  @ViewChild('selectionContainer')
  selectionContainer: ElementRef;

  checkHeightTimerSub = interval(100)
    .pipe(startWith(0), throttleTime(250))
    .subscribe(() => this.updateHeight());

  @Select(RemissionSelectors.getRemissionProcess)
  remissionProcess$: Observable<RemissionProcess>;
  @Select(RemissionSelectors.getRemissionSource)
  remissionSource$: Observable<RemissionResourceType>;
  @Select(RemissionSelectors.getRemissionFilters)
  remissionFilter$: Observable<RemissionSelectedFilters>;
  @Select(RemissionSelectors.getRemissionSupplierId)
  remissionSupplierId$: Observable<number>;
  @Select(RemissionSelectors.getRemissionActiveFilters)
  activeFilters$: Observable<{
    [filterId: string]: string[];
  }>;

  filter$: Observable<Filter[]>;
  filtersByGroup$: Observable<Filter[]>;
  pendingFilters$ = new BehaviorSubject<Filter[]>(null);
  selectedFilter$: Observable<Filter>;
  capacities$: Observable<CapacityType[]>;
  showOverflowInitialMessage$: Observable<boolean>;

  constructor(
    public overlayRef: IsaOverlayRef,
    private filterService: RemissionFilterService,
    private remissionService: RemissionService,
    private renderer: Renderer2,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit() {
    this.getAvailableFilters();
    this.getSelectedFilter();
    this.getPendingFilters();

    this.getRequiredCapacities();
    this.initShowOverflowMessage();
  }

  ngOnDestroy(): void {
    this.checkHeightTimerSub.unsubscribe();
  }

  updateHeight() {
    if (this.selectionContainer) {
      const element: HTMLElement = this.selectionContainer.nativeElement;
      const selectFilterElement: HTMLElement = element.querySelector('app-select-filter');

      if (isNullOrUndefined(selectFilterElement)) {
        return;
      }

      const selectFilterOptionsContent: HTMLElement = selectFilterElement.querySelector('.select-filter-options-content');

      if (isNullOrUndefined(selectFilterOptionsContent)) {
        return;
      }

      const height = element.clientHeight - (selectFilterElement.clientHeight - selectFilterOptionsContent.clientHeight);

      if (selectFilterOptionsContent.offsetHeight !== height) {
        this.renderer.setStyle(selectFilterOptionsContent, 'max-height', `${height}px`);

        this.cdr.markForCheck();
      }
    }
  }

  getAvailableFilters() {
    this.filter$ = this.filterService.filters$;
    this.filtersByGroup$ = this.filterService.filtersByGroup$;
  }

  getSelectedFilter() {
    this.selectedFilter$ = this.filterService.lastFilterGroupChanged$;
  }

  getPendingFilters() {
    this.pendingFilters$ = this.filterService.pendingFilters$;
  }

  getRequiredCapacities() {
    this.capacities$ = this.pendingFilters$.pipe(
      withLatestFrom(this.remissionSource$),
      filter(([_, source]) => source === 'ueberlauf'),
      map(([pendingFilters]) => this.filterService.mapToRemissionFilter(pendingFilters || [])),
      withLatestFrom(this.remissionSupplierId$),
      switchMap(([selectedFilters, supplierId]) => this.remissionService.getCapacities({ selectedFilters, supplierId }))
    );
  }

  initShowOverflowMessage() {
    this.showOverflowInitialMessage$ = this.pendingFilters$.pipe(
      map((pendingFilters) => [pendingFilters, this.filterService.flattenPendingFilters(pendingFilters)]),
      map(([filters, flattenedFilters]: [SelectFilterOption[], SelectFilterOption[]]) => {
        if (isNullOrUndefined(flattenedFilters) || isNullOrUndefined(filters)) {
          return true;
        }

        const departmentFilters = filters.find((f) => f.id === 'abteilungen');

        if (!departmentFilters || !departmentFilters.options) {
          return true;
        }

        const selectedFilters = flattenedFilters.filter((f) => !!f.selected);

        const result = !selectedFilters.some((f) => !!departmentFilters.options.find((opt) => opt.id === f.id));

        return result;
      })
    );
  }

  updateFilter(updatedFilters: SelectFilter[]) {
    this.filterService.updateFilters(updatedFilters);
  }

  onFiltersChange(updatedFilters: SelectFilter[]) {
    this.pendingFilters$.next(updatedFilters);
  }

  applyFilters() {
    if (this.pendingFilters$.value) {
      this.filterService.updateFilters(this.pendingFilters$.value);
    }
    this.close();
  }

  updateLastGroupChanged(updatedGroup: Filter) {
    this.filterService.lastFilterGroupChanged = updatedGroup;
  }

  close() {
    this.animate = 'out';
    this.filterService.resetFilters$.next();

    this.setTransition(true);
  }

  closeAnimationDone() {
    if (this.animate === 'in') {
      this.setTransition(false);
    }

    if (this.animate === 'out') {
      this.overlayRef.close();
    }
  }

  private setTransition(isTransitioning: boolean) {
    this.inTransition = isTransitioning;
  }
}
