import { Component, OnInit, ChangeDetectionStrategy, ViewChild, Renderer2, ElementRef, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { IsaOverlayRef } from 'apps/sales/src/app/core/overlay/isa-overlay-ref';
import { slideIn } from 'apps/sales/src/app/core/overlay';
import { Observable, interval, Subject } from 'rxjs';
import { Filter, SelectFilter } from '../../../filter';
import { ShelfFilterService } from '../../services/shelf-filter.service';
import { map, take, takeUntil } from 'rxjs/operators';
import { isNullOrUndefined } from 'util';
import { ShelfSearchInputComponent } from '../../pages/shelf-search/search';
import { cloneFilter } from '../../../filter/utils';
import { FilterResetStrategy } from '../../../filter/selected-filter-options/components/defs';
import { OverlayContent } from 'apps/sales/src/app/core/overlay/defs';
import { AppService } from '@sales/core-services';

@Component({
  selector: 'app-shelf-filter',
  templateUrl: 'shelf-filter.component.html',
  styleUrls: ['./shelf-filter.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  animations: [slideIn],
})
export class ShelfFilterComponent implements OnInit, OnDestroy {
  animate = 'in';
  resetStrategy: FilterResetStrategy = 'default';
  isIpad = false;
  destroy$ = new Subject<void>();

  @ViewChild('selectionContainer')
  selectionContainer: ElementRef;

  @ViewChild(ShelfSearchInputComponent)
  searchInput: ShelfSearchInputComponent;

  checkHeightTimerSub = interval(100)
    .pipe(takeUntil(this.destroy$))
    .subscribe(() => this.updateHeight());

  filtersByGroup$: Observable<Filter[]>;
  selectedFilter$: Observable<Filter>;
  pendingFilters$: Observable<Filter[]>;
  hasSelectedFilter$: Observable<boolean>;
  filtersChangedFromDefault$: Observable<boolean>;

  constructor(
    private overlayRef: IsaOverlayRef,
    private filterService: ShelfFilterService,
    private renderer: Renderer2,
    private cdr: ChangeDetectorRef,
    private appService: AppService
  ) {}

  ngOnInit() {
    this.getAvailableFilters();
    this.getSelectedFilter();
    this.getPendingFilters();
    this.getHasSelectedFilters();
    this.getFiltersChangedFromDefault();
    this.setDeviceType();
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }

  setDeviceType() {
    this.isIpad = this.appService.isIPadEnv();
  }

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

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

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

  getHasSelectedFilters() {
    this.hasSelectedFilter$ = this.filterService.hasSelectedFilters$;
  }

  getFiltersChangedFromDefault() {
    this.filtersChangedFromDefault$ = this.filterService.filtersChangedFromDefault$;
  }

  onFiltersChange(updatedFilters: SelectFilter[]) {
    this.setPendingFilters(updatedFilters.map(cloneFilter));
    this.setSearchFocus();
  }

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

  setSearchFocus() {
    if (this.searchInput && this.searchInput.searchbar) {
      this.searchInput.searchbar.setFocus('button');
    }
  }

  applyFilters() {
    this.savePendingFilters().subscribe(() => this.initiateSearchAndCloseOverlay());
  }

  close() {
    this.animate = 'out';
    this.filterService.overlayClosed();
  }

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

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

  onResetFilters() {
    if (this.resetStrategy === 'default') {
      this.filterService.resetSelectedFilters();
    }
  }

  setPendingFilters(pendingFilters: Filter[]) {
    this.filterService.pendingFilters = pendingFilters;
  }

  savePendingFilters(): Observable<void> {
    return this.pendingFilters$.pipe(
      take(1),
      map((pendingFilters) => pendingFilters && this.filterService.updateFilters(pendingFilters))
    );
  }

  private initiateSearchAndCloseOverlay() {
    if (this.searchInput) {
      const searchbarValue = (this.searchInput && this.searchInput.searchbar && this.searchInput.searchbar.searchForm.value) || '';

      this.searchInput.triggerSearch({
        type: 'search',
        value: searchbarValue,
        bypassValidation: true,
      });
    }
  }

  private setInitialSearchbarValue(overlayData: OverlayContent<{ queryString: string }>) {
    if (this.hasOverlayData(overlayData) && this.searchbarIsAccessible()) {
      this.searchInput.searchbar.setInputValue(this.getQueryStringFromOverlayData(overlayData));
    }
  }

  private hasOverlayData(overlayData: OverlayContent<{ queryString: string }>): boolean {
    return !!overlayData;
  }

  private searchbarIsAccessible(): boolean {
    return !!this.searchInput && !!this.searchInput.searchbar;
  }

  private getQueryStringFromOverlayData(overlayData: OverlayContent<{ queryString: string }>): string {
    return overlayData.queryString;
  }
}
