import { DestroyRef, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router } from '@angular/router';
import { PickupShelfDetailsStore, PickupShelfStore } from './store';
import { ActionHandlerService } from './services/action-handler.service';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@generated/swagger/oms-api';
import { OrderItemsContext } from '@domain/oms';
import { map } from 'rxjs/operators';
import { coerceBooleanProperty } from '@angular/cdk/coercion';

export abstract class PickupShelfDetailsBaseComponent {
  protected destroyRef = inject(DestroyRef);

  protected router = inject(Router);

  protected activatedRoute = inject(ActivatedRoute);

  protected actionHandlerService = inject(ActionHandlerService);

  store = inject(PickupShelfDetailsStore);
  listStore = inject(PickupShelfStore);

  get side() {
    if (this.activatedRoute.snapshot.queryParams.side !== undefined) {
      return coerceBooleanProperty(this.activatedRoute.snapshot.queryParams.side);
    }
    return true;
  }

  side$ = this.activatedRoute.queryParams.pipe(
    map((params) => {
      if (params.side !== undefined) {
        return coerceBooleanProperty(params.side);
      }
      return true;
    }),
  );

  constructor() {
    this.activatedRoute.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
      // // Fix #4508 - Always Reset Cover Items before fetching new ones inside pickup-shelf-in-details.component
      if (this.store.coverOrderItems?.length) {
        this.store.resetCoverItems();
      }
      this.store.fetchOrder({ orderId: Number(params.orderId) });

      this.store.fetchOrderItems({
        orderNumber: params.orderNumber ? decodeURIComponent(params.orderNumber) : undefined,
        compartmentCode: params.compartmentCode ? decodeURIComponent(params.compartmentCode) : undefined,
        compartmentInfo: params.compartmentInfo ? decodeURIComponent(params.compartmentInfo) : undefined,
        orderItemProcessingStatus: (params.orderItemProcessingStatus
          ? +params.orderItemProcessingStatus
          : undefined) as any,
        orderItemSubsetId: params.orderItemSubsetId ? +params.orderItemSubsetId : undefined,
      });
    });
  }

  /**
   * Führt die Actions aus
   * @param action Actions
   */
  async execAction({
    action,
    latestCompartmentCode,
    latestCompartmentInfo,
  }: {
    action: KeyValueDTOOfStringAndString;
    latestCompartmentCode?: string;
    latestCompartmentInfo?: string;
  }): Promise<OrderItemsContext> {
    if (action.command.includes('FETCHED_PARTIAL')) {
      this.store.setFetchPartial(true);
      return;
    }

    const ctx = await this.actionHandlerService.handle({
      action,
      items: this.store.selectedOrderItems,
      compartmentCode: latestCompartmentCode ?? undefined, // Ticket #4391 - if undefined, assign new compartmentCode to item (bei eingetroffen und drucken)
      compartmentInfo: latestCompartmentInfo ?? (this.store.selectedCompartmentInfo || this.store.compartmentInfo), // Ticket #4397
      order: this.store.order,
      itemQuantity: this.store.selectedOrderItemQuantity,
    });

    const ctxItem = ctx?.items[0];

    // Ticket #4466 - Nach der nachbestellung wurde der Artikel in den Details nicht mehr angezeigt - änderung #4459 rückgängig gemacht
    // Ticket #4459 - Usecase Abholfach Nachbestellen - Wenn das selektierte Item nicht verändert wurde z.B. beim schließen des nachbestellen Modals
    // soll hier returned werden, da der unveränderte Stand angezeigt werden soll
    // if (
    //   !ctxItem ||
    //   (action.command.includes('REORDER') &&
    //     ctxItem.orderItemSubsetId === this.store.selectedOrderItems.find((_) => true).orderItemSubsetId)
    // ) {
    //   return;
    // }

    this.store.setFetchPartial(false);
    this.store.resetSelectedOrderItems();
    this.listStore.resetSelectedListItems();
    this.store.resetSelectedOrderItemQuantity();
    this.store.setSelectedCompartmentInfo(undefined);

    if (!ctxItem) return;

    const updatedDetailsItems = await new Promise<DBHOrderItemListItemDTO[]>((resolve, reject) => {
      this.store.fetchOrderItems({
        orderNumber: ctxItem.orderNumber,
        compartmentCode: ctxItem.processingStatus === 128 ? ctxItem.compartmentCode : undefined,
        compartmentInfo: ctxItem.processingStatus === 128 ? ctxItem.compartmentInfo : undefined,
        orderItemProcessingStatus: ctxItem.processingStatus,
        orderItemSubsetId: ctxItem.orderItemSubsetId,
        done: { resolve, reject },
      });
    });

    ctx.items.forEach((item) => {
      const updatedItem = updatedDetailsItems?.find(
        (detailsItem) => detailsItem?.orderItemSubsetId === item?.orderItemSubsetId,
      );

      if (!updatedItem) return;

      this.listStore.patchOrderItem({
        orderItemSubsetId: item.orderItemSubsetId,
        changes: {
          actions: updatedItem.actions,
          processingStatus: updatedItem.processingStatus,
          compartmentCode: updatedItem.compartmentCode,
          compartmentInfo: updatedItem.compartmentInfo,
          quantity: updatedItem.quantity,
        },
      });
    });

    return ctx;
  }
}
