import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BreadcrumbService } from '@core/breadcrumb';
import { CommandService } from '@core/command';
import { Config } from '@core/config';
import { OrderItemsContext } from '@domain/oms';
import { GoodsInOutOrderGroupItemComponent } from '@shared/goods-in-out';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO } from '@swagger/oms';
import { UiErrorModalComponent, UiModalService } from '@ui/modal';
import { UiScrollContainerComponent } from '@ui/scroll-container';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { first, map, shareReplay, takeUntil } from 'rxjs/operators';
import { GoodsInCleanupListStore } from './goods-in-cleanup-list.store';

@Component({
  selector: 'page-goods-in-cleanup-list',
  templateUrl: 'goods-in-cleanup-list.component.html',
  styleUrls: ['goods-in-cleanup-list.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [GoodsInCleanupListStore],
})
export class GoodsInCleanupListComponent implements OnInit, OnDestroy {
  @ViewChild(UiScrollContainerComponent) scrollContainer: UiScrollContainerComponent;
  @ViewChildren(GoodsInOutOrderGroupItemComponent) listItems: QueryList<GoodsInOutOrderGroupItemComponent>;

  private _scrollPosition: number;

  items$ = this._store.results$;

  itemLength$ = this.items$.pipe(map((items) => items?.length));

  hits$ = this._store.hits$;

  loading$ = this._store.fetching$.pipe(shareReplay());

  selectedOrderItemSubsetIds$ = this._store.selectedOrderItemSubsetIds$;

  get selectedOrderItemSubsetIds() {
    return this._store.selectedOrderItemSubsetIds;
  }

  actions$ = combineLatest([this.items$, this.selectedOrderItemSubsetIds$]).pipe(
    map(([items, selectedOrderItemSubsetIds]) =>
      items?.find((item) => selectedOrderItemSubsetIds?.find((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId))
    ),
    map((item) => item?.actions?.filter((action) => this.selectionRules(action)))
  );

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

  get selectedItems() {
    const items = this._store.results;
    const selectedOrderItemSubsetIds = this.selectedOrderItemSubsetIds;

    return items.filter((item) => selectedOrderItemSubsetIds.some((orderItemSubsetId) => item.orderItemSubsetId === orderItemSubsetId));
  }

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

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

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

  byCompartmentCodeFn = (item: OrderItemListItemDTO) => item.compartmentCode;

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

  private _onDestroy$ = new Subject<void>();

  constructor(
    private _breadcrumb: BreadcrumbService,
    private _store: GoodsInCleanupListStore,
    private _commandService: CommandService,
    private _modal: UiModalService,
    private _route: ActivatedRoute,
    private _router: Router,
    private readonly _config: Config
  ) {}

  ngOnInit(): void {
    this.initInitialSearch();
    this.createBreadcrumb();
    this.removeBreadcrumbs();
  }

  ngOnDestroy(): void {
    this._onDestroy$.next();
    this._onDestroy$.complete();
    this.updateBreadcrumb();
  }

  async createBreadcrumb() {
    await this._breadcrumb.addOrUpdateBreadcrumbIfNotExists({
      key: this._config.get('process.ids.goodsIn'),
      name: 'Abholfachbereinigungsliste',
      path: '/filiale/goods/in/cleanup',
      section: 'branch',
      tags: ['goods-in', 'cleanup'],
    });
  }

  async updateBreadcrumb() {
    const crumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), ['goods-in', 'cleanup'])
      .pipe(first())
      .toPromise();
    for (const crumb of crumbs) {
      this._breadcrumb.patchBreadcrumb(crumb.id, {
        name: crumb.name,
        params: { scroll_position: this.scrollContainer?.scrollPos ?? 0 },
      });
    }
  }

  async removeBreadcrumbs() {
    const detailsCrumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), ['goods-in', 'details'])
      .pipe(first())
      .toPromise();
    const editCrumbs = await this._breadcrumb
      .getBreadcrumbsByKeyAndTags$(this._config.get('process.ids.goodsIn'), ['goods-in', 'edit'])
      .pipe(first())
      .toPromise();

    detailsCrumbs.forEach((crumb) => {
      this._breadcrumb.removeBreadcrumb(crumb.id, true);
    });

    editCrumbs.forEach((crumb) => {
      this._breadcrumb.removeBreadcrumb(crumb.id, true);
    });
  }

  initInitialSearch() {
    if (this._store.hits === 0) {
      this._store.searchResult$.pipe(takeUntil(this._onDestroy$)).subscribe(async (result) => {
        await this.createBreadcrumb();

        if (this._scrollPosition) {
          this.scrollContainer.scrollTo(Number(this._scrollPosition ?? 0));
          this._scrollPosition = undefined;
        }
      });
    }

    this._scrollPosition = this._route.snapshot.queryParams?.scroll_position;
    this._store.search();
  }

  setSelectedItem(item: OrderItemListItemDTO, selected: boolean) {
    const included = this._store.selectedOrderItemSubsetIds.includes(item.orderItemSubsetId);

    if (!included && selected) {
      this._store.patchState({
        selectedOrderItemSubsetIds: [...this._store.selectedOrderItemSubsetIds, item.orderItemSubsetId],
      });
    } else if (included && !selected) {
      this._store.patchState({
        selectedOrderItemSubsetIds: this._store.selectedOrderItemSubsetIds.filter((id) => id !== item?.orderItemSubsetId),
      });
    }
  }

  unselectAll() {
    this.listItems.forEach((listItem) => listItem.setSelected(false));
    this._store.patchState({ selectedOrderItemSubsetIds: [] });
  }

  selectionRules(action: KeyValueDTOOfStringAndString) {
    return action.enabled !== false;
  }

  navigateToDetails(orderItem: OrderItemListItemDTO) {
    const customerNumber = orderItem.buyerNumber;
    const orderNumber = orderItem.orderNumber;
    const processingStatus = orderItem.processingStatus;
    const orderItemId = orderItem.orderItemSubsetId;

    this._router.navigate([
      `/filiale/goods/in/details/customer/${encodeURIComponent(customerNumber)}/order/${encodeURIComponent(
        orderNumber
      )}/item/${orderItemId}/${processingStatus}`,
    ]);
  }

  async handleAction(action: KeyValueDTOOfStringAndString) {
    this.changeActionLoader$.next(true);

    const items = await this.items$.pipe(first()).toPromise();
    const selectedSubsetIds = await this.selectedOrderItemSubsetIds$.pipe(first()).toPromise();
    const itemsToUpdate = items.filter((item) => selectedSubsetIds.includes(item.orderItemSubsetId));
    const itemQuantity = new Map(items.map((item) => [item.orderItemSubsetId, item.quantity]));
    const data: OrderItemsContext = { items: itemsToUpdate, shippingDelayComment: `Aktion: ${action.label}`, itemQuantity };

    try {
      await this._commandService.handleCommand(action.command, data);
      this._store.search();
      this.unselectAll();
    } catch (error) {
      this._modal.open({
        content: UiErrorModalComponent,
        data: error,
      });
      console.error(error);
    }

    this.changeActionLoader$.next(false);
  }
}
