import moment from 'moment';
import { PickupShelfDetailsState } from './pickup-shelf-details.state';
import { DBHOrderItemListItemDTO, KeyValueDTOOfStringAndString } from '@generated/swagger/oms-api';

export const selectOrder = (s: PickupShelfDetailsState) => s.order;

export const selectFetchingOrder = (s: PickupShelfDetailsState) => s.fetchingOrder;

export const selectOrderItemsRaw = (s: PickupShelfDetailsState) => s.orderItems;

export const selectFetchingOrderItems = (s: PickupShelfDetailsState) => s.fetchingOrderItems;

export const selectDisplayedOrderItemProcessingStatus = (s: PickupShelfDetailsState) =>
  s.displayedOrderItemProcessingStatus;

export const selectDisplayedCompartmentCode = (s: PickupShelfDetailsState) =>
  s.displayedCompartmentCode;

export const selectDisplayedCompartmentInfo = (s: PickupShelfDetailsState) =>
  s.displayedCompartmentInfo;

export const selectDisplayedOrderItemSubsetId = (s: PickupShelfDetailsState) =>
  s.displayedOrderItemSubsetId;

export const selectOrderItems = (s: PickupShelfDetailsState): DBHOrderItemListItemDTO[] => {
  let items = selectOrderItemsRaw(s);

  const orderId = selectOrder(s)?.id;
  if (!orderId) {
    return [];
  }

  // Ticket #4348 - Möglicherweise sollte hier stattdessen auf die Buyernumber gefiltert werden, falls nicht alle OrderItems angezeigt werden die angezeigt werden sollten
  items = items?.filter((oi) => oi.orderId === orderId);

  const processingStatus = selectDisplayedOrderItemProcessingStatus(s);
  if (processingStatus) {
    items = items?.filter((oi) => oi.processingStatus === processingStatus);
  }

  const compartmentCode = selectDisplayedCompartmentCode(s);
  if (compartmentCode) {
    items = items?.filter((oi) => oi.compartmentCode === compartmentCode);

    const compartmentInfo = selectDisplayedCompartmentInfo(s);

    if (compartmentInfo) {
      items = items?.filter((oi) => oi.compartmentInfo === compartmentInfo);
    }
  }

  return items ?? [];
};

export const selectNoOrderItemsFound = (s: PickupShelfDetailsState) => {
  return s.fetchingOrderItems === false && selectOrderItems(s)?.length === 0;
};

export const selectCustomer = (s: PickupShelfDetailsState) => s.customer;

export const selectReceipts = (s: PickupShelfDetailsState) => s.receipts;

export const selectFetchingCustomer = (s: PickupShelfDetailsState) => s.fetchingCustomer;

export const selectPickupDeadline = (s: PickupShelfDetailsState) => {
  throw new Error('not implemented');
};

export const selectOrderItemProcessingStatus = (s: PickupShelfDetailsState) => {
  throw new Error('not implemented');
};

export const selectEstimatedDeliveryDate = (s: PickupShelfDetailsState) => {
  throw new Error('not implemented');
};

export const selectCompartment = (s: PickupShelfDetailsState) => {
  const compartmentCode = selectDisplayedCompartmentCode(s);

  if (!compartmentCode) {
    return undefined;
  }

  const compartmentInfo = selectDisplayedCompartmentInfo(s);

  return `${compartmentCode}_${compartmentInfo}`;
};

export const selectFetchPartial = (s: PickupShelfDetailsState) => !!s.fetchPartial;

export const selectFetchReceipts = (s: PickupShelfDetailsState) => !!s.fetchingReceipts;

export const selectSelectedOrderItemIds = (s: PickupShelfDetailsState) =>
  s.selectedOrderItemIds ?? [];

export const selectPreviousSelectedOrderItemSubsetId = (s: PickupShelfDetailsState) =>
  s.previousSelectedOrderItemSubsetId;

export const selectOrderItemSubsetLoading = (s: PickupShelfDetailsState) =>
  s.orderItemSubsetLoading;

export const selectDisableHeaderStatusDropdown = (s: PickupShelfDetailsState) =>
  s.disableHeaderStatusDropdown;

export const selectedOrderItems = (s: PickupShelfDetailsState) => {
  const selectedOrderItemIds = selectSelectedOrderItemIds(s);
  const orderItems = selectOrderItems(s);

  return orderItems?.filter((oi) => selectedOrderItemIds.includes(oi.orderItemSubsetId));
};

export const selectedOrderItem = (s: PickupShelfDetailsState) => {
  const orderItems = selectOrderItems(s);
  const displayedOrderItemSubsetId = selectDisplayedOrderItemSubsetId(s);

  return orderItems?.find((oi) => oi?.orderItemSubsetId === displayedOrderItemSubsetId);
};

export const selectSelectedOrderItemQuantity = (s: PickupShelfDetailsState) => {
  const selectedOrderItemQuantity = s.selectedOrderItemQuantity ?? {};
  const numMap = new Map<number, number>();

  Object.entries(selectedOrderItemQuantity).forEach(([key, value]) => {
    numMap.set(Number(key), value);
  });

  return numMap;
};

export const selectSelectedCompartmentInfo = (s: PickupShelfDetailsState) =>
  s.selectedCompartmentInfo;

export const selectLatestCompartmentCodeAndInfoForOrder = (s: PickupShelfDetailsState) => {
  let coverItems = selectCoverOrderItems(s);

  const orderItems = selectedOrderItems(s);

  /**
   * Ticket #5022 - AHF // Bezahlte und unbezahlte Ware werden auf dieselbe AHF-Nummer gebucht (Abholfach)
   * Fall 1: Wenn alle ausgewählte Order Items Bezahlt sind, darf man diese nur auf die AHF-Nummer buchen, die auch Bezahlt ist.
   * Fall 2: Wenn keines der ausgewählte Order Items Bezahlt sind, darf man nur auf die AHF-Nummer buchen, die auch nicht Bezahlt ist.
   */
  const hasFeaturePaid = orderItems?.every((item) => item.features?.paid === 'Bezahlt');
  const hasSourceKulturPass = orderItems?.every(
    (item) => item.features?.orderSource === 'KulturPass',
  );
  if (hasFeaturePaid || hasSourceKulturPass) {
    coverItems = coverItems?.filter(
      (item) => item.features?.paid === 'Bezahlt' || item.features?.orderSource === 'KulturPass',
    );
  }

  // Ticket #4397 - Sortieren und Filtern der angezeigten CoverItems nach latestCompartmentCode und Info
  const coverItem = coverItems
    // Item should have the processing status 128 "eingetroffen"
    ?.filter((a) => a.processingStatus === 128)
    // Items should be ready for pick up today
    ?.filter((a) => {
      if (a.readyForPickUp) {
        const readyForPickUp = moment(a.readyForPickUp);
        const today = moment.now();

        return readyForPickUp.isSame(today, 'day');
      }
      return false;
    })
    ?.filter((currentItem) => {
      const oderItemPaid = !!coverItems[0].features?.paid;
      const currentItemPaid = !!currentItem.features?.paid;
      return oderItemPaid === currentItemPaid;
    })
    ?.sort((a, b) => new Date(b.readyForPickUp).getTime() - new Date(a.readyForPickUp).getTime())
    ?.find((_) => true);

  return {
    latestCompartmentCode: coverItem?.compartmentCode,
    latestCompartmentInfo: coverItem?.compartmentInfo,
  };
};

export const selectFetchingOrderItemSubsetTasks =
  (orderItemSubsetId: number) => (s: PickupShelfDetailsState) =>
    s.fetchingOrderItemSubsetTasks?.[orderItemSubsetId] ?? false;

export const selectOrderItemSubsetTasks =
  (orderItemSubsetId: number) => (s: PickupShelfDetailsState) =>
    s.orderItemSubsetTasks?.[orderItemSubsetId] ?? [];

export const selectNotifications = (orderItemSubsetId: number) => (s: PickupShelfDetailsState) => {
  const tasks = selectOrderItemSubsetTasks(orderItemSubsetId)(s);

  return tasks
    .sort((a, b) => new Date(b.completed).getTime() - new Date(a.completed).getTime())
    .reduce(
      (data, result) => {
        (data[result.name] = data[result.name] || []).push(new Date(result.completed));
        return data;
      },
      {} as Record<string, Date[]>,
    );
};

export const selectLatestNotificationDatesFor =
  (orderItemSubsetId: number, keys: string[]) => (s: PickupShelfDetailsState) => {
    const notifications = selectNotifications(orderItemSubsetId)(s);
    const dates: Array<{ type: string; dates: Date[] }> = [];

    for (const key of keys) {
      const notification = notifications?.[key] ?? [];

      const validDates = notification.filter((date) => {
        // check if curr is an invalid date
        return !isNaN(date.getTime());
      });

      const mappedDates = { type: key, dates: validDates };

      if (mappedDates.dates?.length > 0) {
        dates.push(mappedDates);
      }
    }
    return dates;
  };

export const selectLatestEmailNotificationDates =
  (orderItemSubsetId: number) => (s: PickupShelfDetailsState) => {
    return selectLatestNotificationDatesFor(orderItemSubsetId, [
      'NOTIFICATION_EMAIL',
      'REMINDER_EMAIL',
      'ORDERCONFIRMATION_EMAIL',
    ])(s);
  };

export const selectLatestSmsNotificationDate2 =
  (orderItemSubsetId: number) => (s: PickupShelfDetailsState) => {
    return selectLatestNotificationDatesFor(orderItemSubsetId, ['NOTIFICATION_SMS'])(s);
  };

export const selectCanSelectAction = (s: PickupShelfDetailsState) => {
  const items = selectOrderItems(s);
  const selectedOrderItemIds = selectSelectedOrderItemIds(s);
  const actionsDisabled = selectDisableHeaderStatusDropdown(s);

  if (items?.length === 1 && !actionsDisabled) {
    return true;
  }

  if (selectedOrderItemIds.length > 0 && !actionsDisabled) {
    return true;
  }

  return false;
};

export const selectShowTagsComponent = (s: PickupShelfDetailsState) => {
  const items = selectOrderItems(s);
  const orderFetching = selectFetchingOrder(s);
  const firstItem = items?.find((_) => true);

  const hasArrivedAction = firstItem?.actions?.some((a) => a.command?.includes('ARRIVED'));
  return hasArrivedAction && !orderFetching;
};

export const selectAddToPreviousCompartmentAction = (s: PickupShelfDetailsState) => {
  const items = selectOrderItems(s);
  const latestCompartmentInfos = selectLatestCompartmentCodeAndInfoForOrder(s);
  const firstItem = items?.find((_) => true);

  if (
    [16, 8192].includes(firstItem?.processingStatus) &&
    latestCompartmentInfos?.latestCompartmentCode
  ) {
    // Zubuchen von Bezahlte und unbezahlte Bestellungen nicht möglich
    // Zubuchen bei Pay&Collect nur innerhalb der gleichen Bestellung möglich

    return firstItem.actions.find((a) => a.key === '128');
  }

  return undefined;
};

export const selectMainActions = (s: PickupShelfDetailsState) => {
  const items = selectOrderItems(s);
  const fetchPartial = selectFetchPartial(s);
  const firstItem = items?.find((_) => true);

  return firstItem?.actions
    ?.filter((action) => typeof action?.enabled !== 'boolean')
    ?.filter((action) => (fetchPartial ? !action.command.includes('FETCHED_PARTIAL') : true));
};

export const selectShelfOutMainActions = (s: PickupShelfDetailsState) => {
  const items = selectOrderItems(s);
  const fetchPartial = selectFetchPartial(s);

  // Ticket #4690 Consider every Item for selecting the main actions in Details View - Only for PickUpShelfOut
  const actions: KeyValueDTOOfStringAndString[] = [];
  for (const item of items) {
    const actionsFromItem = item?.actions
      ?.filter((action) => typeof action?.enabled !== 'boolean')
      ?.filter((action) => (fetchPartial ? !action.command.includes('FETCHED_PARTIAL') : true));
    for (const action of actionsFromItem) {
      if (!actions.find((a) => a.command === action.command)) {
        actions.push(action);
      }
    }
  }

  return actions;
};

export const selectCustomerNumber = (s: PickupShelfDetailsState) => {
  const order = selectOrder(s);
  return order?.buyer?.buyerNumber;
};

export const selectFetchingCoverOrderItems = (s: PickupShelfDetailsState) =>
  s.fetchingCoverOrderItems ?? false;

export const selectCoverOrderItems = (s: PickupShelfDetailsState) => {
  const coverItems = s.coverOrderItems ?? [];
  const selected = selectedOrderItem(s);

  return coverItems.filter((item) => item.buyerNumber === selected?.buyerNumber);
};
