import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { Component, ChangeDetectionStrategy, OnInit, OnDestroy, ViewChild, ViewChildren, QueryList } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ApplicationService } from '@core/application';
import { BreadcrumbService } from '@core/breadcrumb';
import { Config } from '@core/config';
import { RemissionListItem } from '@domain/remission';
import { SupplierDTO } from '@swagger/remi';
import { Subject, combineLatest, BehaviorSubject } from 'rxjs';
import { debounceTime, first, map, shareReplay, takeUntil, withLatestFrom } from 'rxjs/operators';
import { RemissionListItemComponent } from './remission-list-item';
import { RemissionListComponentStore } from './remission-list.component-store';
import { RemissionComponentStore } from './remission.component-store';

@Component({
  selector: 'page-remission-list',
  templateUrl: 'remission-list.component.html',
  styleUrls: ['remission-list.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [RemissionComponentStore],
})
export class RemissionListComponent implements OnInit, OnDestroy {
  @ViewChildren(RemissionListItemComponent) listItems: QueryList<RemissionListItemComponent>;
  @ViewChild('scrollContainer', { static: true })
  scrollContainer: CdkVirtualScrollViewport;

  private _onDestroy$ = new Subject();

  get processId() {
    return this._config.get('process.ids.remission');
  }

  get suppliers$() {
    return this._remissionListStore.suppliers$;
  }

  get selectedSupplier$() {
    return this._remissionListStore.selectedSupplier$;
  }

  get selectedSupplierId$() {
    return this._remissionListStore.selectedSupplier$.pipe(map((s) => s?.id));
  }

  get sources$() {
    return this._remissionListStore.sources$;
  }

  get selectedSource$() {
    return this._remissionListStore.selectedSource$;
  }

  get items$() {
    return this._remissionListStore.items$;
  }

  get requiredCapacities$() {
    return this._remissionListStore.requiredCapacities$;
  }

  get hits$() {
    return this._remissionListStore.hits$;
  }

  get fetching$() {
    return this._remissionListStore.fetching$;
  }

  get return$() {
    return this._remissionStore.return$;
  }

  get filter$() {
    return this._remissionListStore.filter$;
  }

  showSelectDepartmenttext$ = combineLatest([this.filter$, this.selectedSource$]).pipe(
    map(([filter, source]) => {
      if (source !== 'Abteilungsremission') {
        return false;
      }

      if (!!filter?.getQueryToken()?.filter?.abteilungen) {
        return false;
      }

      return true;
    })
  );

  listEmpty$ = combineLatest([this.fetching$, this.hits$]).pipe(
    map(([loading, hits]) => !loading && hits === 0),
    shareReplay()
  );

  get queryParams$() {
    return this._activatedRoute.queryParams.pipe(
      withLatestFrom(this._remissionListStore.filter$, this.selectedSupplierId$, this.selectedSource$),
      map(([params, filter, supplier, source]) => {
        let queryParams = params;
        if (filter) {
          queryParams = { ...filter.getQueryParams(), ...params, supplier, source };
        }
        return queryParams;
      })
    );
  }

  get returnCount$() {
    return this._remissionStore.returnCount$;
  }

  showStartRemissionAction$ = combineLatest([this.listEmpty$, this.return$]).pipe(map(([empty, r]) => !empty && !r));

  filteredSuppliers$ = combineLatest([this._remissionStore.uncompleted$, this.suppliers$, this.selectedSupplier$]).pipe(
    map(([uncompleted, suppliers, selectedSupplier]) => {
      if (!uncompleted) {
        return suppliers;
      }
      return suppliers.filter((supplier) => supplier?.id === selectedSupplier?.id);
    })
  );

  trackByItemId = (item: RemissionListItem) => item?.dto?.id;

  showScrollArrow$ = new BehaviorSubject<boolean>(false);

  constructor(
    private readonly _remissionListStore: RemissionListComponentStore,
    private readonly _remissionStore: RemissionComponentStore,
    private readonly _router: Router,
    private readonly _activatedRoute: ActivatedRoute,
    private readonly _breadcrumb: BreadcrumbService,
    private readonly _applicationService: ApplicationService,
    private readonly _config: Config
  ) {}

  ngOnInit() {
    this._activatedRoute.queryParams.pipe(takeUntil(this._onDestroy$), debounceTime(0)).subscribe(async (queryParams) => {
      const { supplier, source } = queryParams;

      if (supplier) {
        this._remissionListStore.setSelectedSupplierId(+supplier);
      }

      if (source) {
        this._remissionListStore.setSelectedSource(source);
      }

      const data = this._remissionListStore.getCachedData();
      if (data.items?.length !== 0) {
        this._remissionListStore.setItems(data.items);
        this._remissionListStore.setHits(data.hits);
        this.scrollTop(Number(queryParams?.scroll_position ?? 0));
      }

      await this.updateBreadcrumb(queryParams);
      await this.removeBreadcrumbs();
    });

    this._remissionListStore.filter$
      .pipe(takeUntil(this._onDestroy$), withLatestFrom(this._remissionListStore.selectedSource$))
      .subscribe(([_, source]) => {
        if (source === 'Abteilungsremission') {
          this._remissionListStore.loadRequiredCapacities();
        }
      });

    this._activatedRoute.params.pipe(takeUntil(this._onDestroy$)).subscribe((params) => {
      const id = +params.returnId;
      if (!!id) {
        // Remission wurde gestartet
        this._remissionStore.getReturn(id);
      } else {
        // Für die Anzahl der Warenbegleitscheine, wenn keine Remission gestartet wurde
        this._remissionStore.getReturns(false);
      }
    });

    this._remissionStore.getReturnCompleted.pipe(takeUntil(this._onDestroy$)).subscribe((returnDto) => {
      if (!!returnDto) {
        this._remissionListStore.setSelectedSupplierId(returnDto.supplier.id);
      }

      if (!returnDto || !!returnDto.completed) {
        this._applicationService.patchProcessData(this._remissionListStore.processId, {
          active: undefined,
        });
        this._router.navigate(['./'], { relativeTo: this._activatedRoute.parent });
      }
    });
  }

  async ngOnDestroy() {
    this._onDestroy$.next();
    this._onDestroy$.complete();

    if (!!this._remissionStore.return) {
      this._remissionListStore.cacheCurrentData();
      const params = await this._activatedRoute.queryParams.pipe(first()).toPromise();
      await this.updateBreadcrumb(params);
    }
  }

  async updateBreadcrumb(queryParams: Record<string, string> = {}) {
    const scroll_position = this.scrollContainer.measureScrollOffset('top');
    const returnId = this._activatedRoute?.snapshot?.params?.returnId;

    const crumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._remissionListStore.processId, ['remission'])
      .pipe(first())
      .toPromise();

    const params = { ...queryParams, scroll_position };
    for (const crumb of crumbs) {
      this._breadcrumb.patchBreadcrumb(crumb.id, {
        params,
        path: `/filiale/remission/${returnId ? returnId + '/' : ''}list`,
      });
    }
  }

  async scrolledIndexChange(index: number) {
    const items = await this.items$.pipe(first()).toPromise();
    const hits = await this.hits$.pipe(first()).toPromise();

    if (index > 0) {
      this.showScrollArrow$.next(true);
    } else {
      this.showScrollArrow$.next(false);
    }

    if (items.length >= hits) {
      return;
    }

    if (this._activatedRoute.snapshot.fragment === 'shipping-document') {
      return;
    }

    if (index >= items.length - 10 && items.length - 10 > 0 && !this._remissionListStore.fetching) {
      this._remissionListStore.search({});
    }
  }

  scrollTop(scrollPos: number) {
    setTimeout(() => this.scrollContainer.scrollTo({ top: scrollPos, behavior: 'smooth' }), 0);
  }

  setSupplier(supplier: SupplierDTO) {
    this._remissionListStore.setSupplier(supplier);
  }

  setSource(source: string) {
    this._remissionListStore.setSource(source);
  }

  async removeBreadcrumbs() {
    await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'shipping-documents']);
    await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'add-product']);
    await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'create']);
    await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'finish-shipping-document']);
    await this._breadcrumb.removeBreadcrumbsByKeyAndTags(this._remissionListStore.processId, ['remission', 'finish-remission']);
  }

  shippingDocumentDeleted() {
    this._router.navigate(['/filiale', 'remission', 'list']);
  }
}
