import { OnDestroy } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';
import { KeyValueDTOOfStringAndString, OrderItemListItemDTO, ReceiptDTO } from '@swagger/oms';
import { isEqual } from 'lodash';
import { combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export interface SharedGoodsInOutOrderDetailsComponentState {
  orderItems: OrderItemListItemDTO[];
  coverItems: OrderItemListItemDTO[];
  receipts: ReceiptDTO[];
  compartmentInfo?: string;
  latestCompartmentCode?: string;
  latestCompartmentInfo?: string;
  fetchPartial?: boolean;
  itemsSelectable?: boolean;
  selectedeOrderItemSubsetIds: number[];
}

export abstract class SharedGoodsInOutOrderDetailsStore extends ComponentStore<SharedGoodsInOutOrderDetailsComponentState>
  implements OnDestroy {
  abstract itemsSelectable: boolean;

  abstract itemsSelectable$: Observable<boolean>;

  get orderItems() {
    return this.get((s) => s.orderItems);
  }
  set orderItems(orderItems: OrderItemListItemDTO[]) {
    if (!isEqual(this.orderItems, orderItems)) {
      this.patchState({ orderItems });
    }
  }

  orderItems$ = this.select((s) => s.orderItems);

  get coverItems() {
    return this.get((s) => s.coverItems);
  }
  set coverItems(coverItems: OrderItemListItemDTO[]) {
    if (!isEqual(this.coverItems, coverItems)) {
      this.patchState({ coverItems });
    }
  }

  coverItems$ = this.select((s) => s.coverItems);

  get selectedeOrderItemSubsetIds() {
    return this.get((s) => s.selectedeOrderItemSubsetIds);
  }
  set selectedeOrderItemSubsetIds(selectedeOrderItemSubsetIds: number[]) {
    if (!isEqual(this.selectedeOrderItemSubsetIds, selectedeOrderItemSubsetIds)) {
      this.patchState({ selectedeOrderItemSubsetIds });
    }
  }

  selectedeOrderItemSubsetIds$ = this.select((s) => s.selectedeOrderItemSubsetIds);

  get compartmentInfo() {
    return this.get((s) => s.compartmentInfo);
  }
  set compartmentInfo(compartmentInfo: string) {
    if (this.compartmentInfo !== compartmentInfo) {
      this.patchState({ compartmentInfo });
    }
  }

  compartmentInfo$ = this.select((s) => s.compartmentInfo);

  get fetchPartial() {
    return this.get((s) => s.fetchPartial);
  }

  fetchPartial$ = this.select((s) => s.fetchPartial);

  mainActions$ = combineLatest([this.orderItems$, this.fetchPartial$]).pipe(
    map(([orderItems, fetchPartial]) =>
      orderItems
        ?.find((_) => true)
        ?.actions?.filter((action) => typeof action?.enabled !== 'boolean')
        ?.filter((action) => (fetchPartial ? !action.command.includes('FETCHED_PARTIAL') : true))
        ?.sort((a, b) => (a.selected === b.selected ? 0 : a.selected ? -1 : 1))
    )
  );

  showTagsComponent$ = this.orderItems$.pipe(
    map((orderItems) => {
      const first = orderItems?.find((_) => true);
      return first?.actions?.some((a) => a.command?.includes('ARRIVED')) || false;
    })
  );

  get latestCompartmentCode() {
    return this.get((s) => s.latestCompartmentCode);
  }

  set latestCompartmentCode(latestCompartmentCode: string) {
    if (this.latestCompartmentCode !== latestCompartmentCode) {
      this.patchState({ latestCompartmentCode });
    }
  }

  readonly latestCompartmentCode$ = combineLatest([
    this.select((s) => s.latestCompartmentCode),
    this.select((s) => s.latestCompartmentInfo),
  ]).pipe(
    map(([code, info]) => {
      if (!!info) {
        return `${code}_${info}`;
      }
      return code;
    })
  );

  get latestCompartmentInfo() {
    return this.get((s) => s.latestCompartmentInfo);
  }

  set latestCompartmentInfo(latestCompartmentInfo: string) {
    if (this.latestCompartmentInfo !== latestCompartmentInfo) {
      this.patchState({ latestCompartmentInfo });
    }
  }

  readonly latestCompartmentInfo$ = this.select((s) => s.latestCompartmentInfo);

  addToPreviousCompartmentAction$ = combineLatest([this.orderItems$, this.coverItems$, this.latestCompartmentCode$]).pipe(
    map(([orderItems, coverItems, latestCompartmentCode]) => {
      const orderItem = orderItems[0];

      if ([16, 8192].includes(orderItem?.processingStatus) && latestCompartmentCode) {
        if (orderItem.features?.paid) {
          // Zubuchen von Bezahlte und unbezahlte Bestellungen nicht möglich
          // Zubuchen bei Pay&Collect nur innerhalb der gleichen Bestellung möglich
          if (
            coverItems.find((i) => {
              let compartmentCode = i.compartmentCode;
              if (!!i.compartmentInfo) {
                compartmentCode = `${i.compartmentCode}_${i.compartmentInfo}`;
              }

              return compartmentCode === latestCompartmentCode && i.orderNumber === orderItem.orderNumber;
            })?.features?.paid === orderItem?.features?.paid
          ) {
            return orderItem.actions.find((a) => a.key === '128');
          }
        } else {
          return orderItem.actions.find((a) => a.key === '128');
        }
      }

      return undefined;
    })
  );

  constructor() {
    super({
      orderItems: [],
      selectedeOrderItemSubsetIds: [],
      receipts: [],
      coverItems: [],
    });
  }

  updateOrderItems(orderItems: OrderItemListItemDTO[]) {
    this.patchState({
      orderItems: this.orderItems.map((item) => {
        const newItem = orderItems.find((i) => i.orderItemSubsetId === item.orderItemSubsetId);
        return newItem ? newItem : item;
      }),
    });
  }

  updateReceipts(receipts: ReceiptDTO[]) {
    this.patchState({
      receipts,
    });
  }

  abstract handleAction(action: KeyValueDTOOfStringAndString, { compartmentCode }: { compartmentCode?: string }): Promise<void>;

  selectAllOrderItems() {
    this.patchState({ selectedeOrderItemSubsetIds: this.orderItems?.map((item) => item.orderItemSubsetId) });
  }

  selectOrderItem(item: OrderItemListItemDTO, selected: boolean) {
    const included = this.selectedeOrderItemSubsetIds.includes(item?.orderItemSubsetId);

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