import {
  Subject,
  fromEvent,
  combineLatest,
  Observable,
  BehaviorSubject,
} from 'rxjs';

import {
  Component,
  OnDestroy,
  OnInit,
  ViewChild,
  ElementRef,
  ChangeDetectionStrategy,
} from '@angular/core';
import { SearchStateFacade } from 'apps/sales/src/app/store/customer';
import {
  first,
  takeUntil,
  map,
  debounceTime,
  filter,
  withLatestFrom,
} from 'rxjs/operators';
import { groupBy } from 'apps/sales/src/app/utils';
import { OrderItemListItemDTO } from '@swagger/oms';
import { ShelfNavigationService } from '../../shared/services';
import { Store, Select } from '@ngxs/store';
import { ProcessSelectors } from 'apps/sales/src/app/core/store/selectors/process.selectors';
import { ORDER_DETAILS_PREFIX } from './order-details-prefix';

@Component({
  selector: 'app-shelf-search-results',
  templateUrl: './shelf-search-results.component.html',
  styleUrls: ['./shelf-search-results.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShelfSearchResultsComponent implements OnInit, OnDestroy {
  @ViewChild('scroll', { static: true })
  scrollContainer: ElementRef;

  @Select(ProcessSelectors.getCurrentProcessId) currentProcessId$: Observable<
    number
  >;

  destroy$ = new Subject();
  isFetching$ = new BehaviorSubject<boolean>(false);

  grouped$ = this.searchStateFacade.result$.pipe(
    map((results) => groupBy(results, (item) => (item ? item.buyerNumber : '')))
  );

  fetching$ = this.searchStateFacade.fetching$;

  scrollStorageKey = ORDER_DETAILS_PREFIX;

  constructor(
    private searchStateFacade: SearchStateFacade,
    private shelfNavigationService: ShelfNavigationService,
    private store: Store
  ) {}

  ngOnInit() {
    this.initScrollContainer();
    this.fetch();
  }

  initScrollContainer() {
    const scrollContainer: HTMLElement = this.scrollContainer.nativeElement;
    fromEvent(scrollContainer, 'scroll')
      .pipe(takeUntil(this.destroy$), withLatestFrom(this.fetching$))
      .subscribe(([_, isFetching]) => {
        if (this.reachedBottom() && !isFetching) {
          this.fetch(true);
        }
      });
  }

  reachedBottom() {
    const scrollContainer: HTMLElement = this.scrollContainer.nativeElement;
    return (
      scrollContainer.scrollHeight -
        (scrollContainer.scrollTop + scrollContainer.clientHeight) -
        100 <=
      0
    );
  }

  async fetch(force = false) {
    const [hits, result, fetching] = await combineLatest([
      this.searchStateFacade.hits$,
      this.searchStateFacade.result$,
      this.fetching$,
    ])
      .pipe(first())
      .toPromise();

    if (
      (force && this.resultListNotFullyLoaded(hits, result.length || 0)) ||
      !hits ||
      (!result.length && !fetching)
    ) {
      await this.searchStateFacade.fetchResult({});
    }
  }

  navigateToDetails(orderItemListItem: OrderItemListItemDTO) {
    this.shelfNavigationService.navigateToDetails(orderItemListItem);
  }

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

  private resultListNotFullyLoaded(
    hits: number,
    numberOfFetchedResults: number
  ): boolean {
    return numberOfFetchedResults < hits;
  }
}
