import { AsyncPipe } from '@angular/common';
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  OnInit,
  QueryList,
  TrackByFunction,
  ViewChild,
  ViewChildren,
  inject,
} from '@angular/core';
import { ActivatedRoute, NavigationStart, Router, RouterLink } from '@angular/router';
import { Filter, FilterModule } from '@shared/components/filter';
import { IconModule } from '@shared/components/icon';
import { PickUpShelfListItemComponent } from '../../shared/pickup-shelf-list-item/pickup-shelf-list-item.component';
import { Group, GroupByPipe } from '@ui/common';
import { UiSpinnerModule } from '@ui/spinner';
import { PickupShelfInNavigationService } from '@shared/services/navigation';
import { map } from 'rxjs/operators';
import { DBHOrderItemListItemDTO } from '@generated/swagger/oms-api';
import { Observable, combineLatest, of } from 'rxjs';
import { PickupShelfDetailsStore, PickupShelfStore } from '../../store';
import { isEqual } from 'lodash';
import { EnvironmentService } from '@core/environment';
import { CacheService } from '@core/cache';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { PickupShelfListItemLoaderComponent } from '../../shared/pickup-shelf-list-item/pickup-shelf-list-item-loader.component';
import { ScrollContainerDirective } from '@shared/directives/scroll-container';
import { MatomoModule } from 'ngx-matomo-client';

@Component({
  selector: 'page-pickup-shelf-in-list',
  templateUrl: 'pickup-shelf-in-list.component.html',
  styleUrls: ['pickup-shelf-in-list.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: { class: 'page-pickup-shelf-in-list' },
  imports: [
    AsyncPipe,
    RouterLink,
    IconModule,
    FilterModule,
    PickUpShelfListItemComponent,
    ScrollContainerDirective,
    GroupByPipe,
    UiSpinnerModule,
    PickupShelfListItemLoaderComponent
],
})
export class PickUpShelfInListComponent implements OnInit, AfterViewInit {
  @ViewChildren(PickUpShelfListItemComponent) listItems: QueryList<PickUpShelfListItemComponent>;
  @ViewChild(ScrollContainerDirective) scrollContainer: ScrollContainerDirective;

  private _pickupShelfInNavigationService = inject(PickupShelfInNavigationService);

  store = inject(PickupShelfStore);
  detailsStore = inject(PickupShelfDetailsStore);
  destroyRef = inject(DestroyRef);

  list$ = this.store.list$;

  hits$ = this.store.listHits$;

  filterNavigation = this._pickupShelfInNavigationService.filterRoute();

  get primaryOutletActive$() {
    return this._environment.matchDesktop$.pipe(map((matches) => matches && this._activatedRoute.outlet === 'primary'));
  }

  filter$ = this.store.filter$;

  hasFilter$ = combineLatest([this.filter$, this.store.defaultFilter$]).pipe(
    map(([filter, defaultFilter]) => {
      const filterQueryParams = filter?.getQueryParams();
      return !isEqual(filterQueryParams, Filter.create(defaultFilter).getQueryParams());
    }),
  );

  fetching$: Observable<boolean> = this.store.fetchingList$;

  searchboxHint$ = this.store.searchboxHint$;

  get isTablet$() {
    return this._environment.matchTablet$;
  }

  get isDesktopSmall$() {
    return this._environment.matchDesktopSmall$;
  }

  get selectedIds$() {
    return this.store.selectedListItems$.pipe(map((items) => items?.map((item) => item.orderItemSubsetId)));
  }

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

  byBuyerNumberFn = (item: DBHOrderItemListItemDTO) => item.buyerNumber;

  byOrderNumberFn = (item: DBHOrderItemListItemDTO) => item.orderNumber;

  byProcessingStatusFn = (item: DBHOrderItemListItemDTO) => item.processingStatus;

  byCompartmentCodeFn = (item: DBHOrderItemListItemDTO) =>
    item.compartmentInfo ? `${item.compartmentCode}_${item.compartmentInfo}` : item.compartmentCode;

  trackByFn: TrackByFunction<DBHOrderItemListItemDTO> = (index, item) =>
    `${item.orderId}${item.orderItemId}${item.orderItemSubsetId}`;

  trackByGroupFn: TrackByFunction<Group<string, DBHOrderItemListItemDTO>> = (index, group) => group.group;

  private readonly SCROLL_POSITION_TOKEN = 'SHELF_IN_LIST_SCROLL_POSITION';

  constructor(
    private _environment: EnvironmentService,
    private _activatedRoute: ActivatedRoute,
    private _pickUpShelfInNavigation: PickupShelfInNavigationService,
    private _cache: CacheService,
    private _router: Router,
  ) {}

  ngOnInit() {
    combineLatest([this.store.processId$, this._activatedRoute.queryParams])
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(async ([_, queryParams]) => {
        if (
          !this.store.list.length ||
          !isEqual(queryParams, this.cleanupQueryParams(this.store.filter.getQueryParams()))
        ) {
          this.store.setQueryParams(queryParams);
          this.store.fetchList({ emitFetchListResponse: false });
        }

        const scrollPos = await this._getScrollPositionFromCache();
        if (!!scrollPos && this._activatedRoute.outlet === 'primary') {
          setTimeout(() => {
            this.scrollContainer?.scrollTo(scrollPos);
            this._removeScrollPositionFromCache();
          }, 150);
        }
      });

    this._router.events.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
      if (event instanceof NavigationStart) {
        this._addScrollPositionToCache();
      }
    });
  }

  ngAfterViewInit(): void {
    this.scrollItemIntoView();
  }

  cleanupQueryParams(params: Record<string, string> = {}) {
    const clean = { ...params };

    for (const key in clean) {
      if (Object.prototype.hasOwnProperty.call(clean, key)) {
        if (clean[key] == undefined) {
          delete clean[key];
        }
      }
    }

    return clean;
  }

  private _removeScrollPositionFromCache(): void {
    this._cache.delete({ processId: this.store.processId, token: this.SCROLL_POSITION_TOKEN });
  }

  private _addScrollPositionToCache(): void {
    if (this._activatedRoute.outlet === 'primary') {
      this._cache.set<number>(
        { processId: this.store.processId, token: this.SCROLL_POSITION_TOKEN },
        this.scrollContainer?.scrollPosition,
      );
    }
  }

  private async _getScrollPositionFromCache(): Promise<number> {
    return await this._cache.get<number>({ processId: this.store.processId, token: this.SCROLL_POSITION_TOKEN });
  }

  // After Navigating to Result Side Outlet
  scrollItemIntoView() {
    setTimeout(() => {
      const getPrimaryRouteParams = this._activatedRoute.parent?.children[0]?.snapshot?.params;
      const item = this.listItems?.find((item) => item.item.orderId === Number(getPrimaryRouteParams?.orderId));
      item?.scrollIntoView();
    }, 150);
  }

  getItemDetailsLink(item: DBHOrderItemListItemDTO) {
    return this._pickUpShelfInNavigation.detailRoute({
      item: {
        orderId: item?.orderId,
        orderNumber: item?.orderNumber,
        compartmentCode: item?.compartmentCode,
        processingStatus: item?.processingStatus,
        orderItemSubsetId: item?.orderItemSubsetId,
        compartmentInfo: item?.compartmentInfo,
      },
    }).path;
  }

  search(filter: Filter) {
    this.store.setQueryParams(filter.getQueryParams());
    this.store.fetchList();
  }

  loadMore() {
    console.log('loadMore');
    this.store.fetchMoreList();
  }
}
