import {
  EntityDTOContainerOfShoppingCartItemDTO,
  DestinationDTO,
} from '@generated/swagger/checkout-api';
import { EntityContainer } from '@isa/common/data-access';

/**
 * Shipping target constants used in checkout logic.
 *
 * @remarks
 * These constants represent different shipping/destination target types:
 * - STANDARD_DELIVERY: Standard shipping destination (value: 2)
 * - B2B_DELIVERY: Business-to-business shipping destination (value: 16)
 */
export const ShippingTargets = {
  /** Standard delivery shipping target (value: 2) */
  STANDARD_DELIVERY: 2,
  /** B2B delivery shipping target (value: 16) */
  B2B_DELIVERY: 16,
} as const;

/**
 * Filters shopping cart items to only include shipping items (DIG-Versand and B2B-Versand).
 *
 * @remarks
 * Pure filter function that identifies items requiring special shipping handling:
 * - DIG-Versand: Digital delivery items
 * - B2B-Versand: Business-to-business delivery items
 *
 * These items require branch and logistician assignment before checkout completion.
 * Used in the updateShippingAvailabilities workflow.
 *
 * @param items - Shopping cart items to filter
 * @returns Array containing only shipping items (DIG-Versand and B2B-Versand)
 *
 * @example
 * ```typescript
 * const items = [
 *   { data: { features: { orderType: 'Versand' } } },
 *   { data: { features: { orderType: 'DIG-Versand' } } },
 *   { data: { features: { orderType: 'B2B-Versand' } } }
 * ];
 * const shippingItems = filterShippingItems(items);
 * // Returns: 2 items (DIG-Versand and B2B-Versand)
 * ```
 */
export function filterShippingItems(
  items: EntityDTOContainerOfShoppingCartItemDTO[],
): EntityDTOContainerOfShoppingCartItemDTO[] {
  return items.filter(
    (item) =>
      item.data?.features?.['orderType'] === 'DIG-Versand' ||
      item.data?.features?.['orderType'] === 'B2B-Versand',
  );
}

/**
 * Filters destinations to only include standard and B2B delivery destinations.
 *
 * @remarks
 * Pure filter function that identifies destinations requiring shipping address updates:
 * - target === 2 (STANDARD_DELIVERY): Standard shipping destinations
 * - target === 16 (B2B_DELIVERY): Business-to-business shipping destinations
 *
 * Used in the updateDestinationShippingAddresses workflow to determine which
 * destinations need their shipping address information updated.
 *
 * @param destinations - Destination containers to filter
 * @returns Array containing only delivery destinations (target 2 or 16)
 *
 * @example
 * ```typescript
 * const destinations = [
 *   { id: 1, data: { target: 2 } },  // Standard delivery
 *   { id: 2, data: { target: 1 } },  // Pickup (excluded)
 *   { id: 3, data: { target: 16 } }  // B2B delivery
 * ];
 * const deliveryDestinations = filterDeliveryDestinations(destinations);
 * // Returns: 2 destinations (targets 2 and 16)
 * ```
 */
export function filterDeliveryDestinations(
  destinations: EntityContainer<DestinationDTO>[],
): EntityContainer<DestinationDTO>[] {
  return destinations.filter(
    (dest) =>
      dest.data?.target === ShippingTargets.STANDARD_DELIVERY ||
      dest.data?.target === ShippingTargets.B2B_DELIVERY,
  );
}

/**
 * Type guard to check if a shopping cart item has a valid item ID and product data.
 *
 * @remarks
 * Used to safely filter items before performing operations that require
 * both the container ID and product information.
 *
 * @param item - Shopping cart item to validate
 * @returns true if item has both id and data.product, false otherwise
 *
 * @example
 * ```typescript
 * const items = [
 *   { id: 1, data: { product: {...} } },  // Valid
 *   { id: 2, data: null },                // Invalid
 *   { id: undefined, data: { product: {...} } }  // Invalid
 * ];
 * const validItems = items.filter(hasValidItemId);
 * // Returns: 1 item (first one)
 * ```
 */
export function hasValidItemId(
  item: EntityDTOContainerOfShoppingCartItemDTO,
): item is EntityDTOContainerOfShoppingCartItemDTO & {
  id: number;
  data: NonNullable<EntityDTOContainerOfShoppingCartItemDTO['data']> & {
    product: NonNullable<
      NonNullable<EntityDTOContainerOfShoppingCartItemDTO['data']>['product']
    >;
  };
} {
  return (
    typeof item.id === 'number' &&
    item.data !== null &&
    item.data !== undefined &&
    item.data.product !== null &&
    item.data.product !== undefined
  );
}

/**
 * Type guard to check if a destination has valid data and ID.
 *
 * @remarks
 * Used to safely filter destinations before performing update operations
 * that require both the container ID and destination data.
 *
 * @param destination - Destination container to validate
 * @returns true if destination has both id and data, false otherwise
 *
 * @example
 * ```typescript
 * const destinations = [
 *   { id: 1, data: { target: 2 } },  // Valid
 *   { id: 2, data: null },           // Invalid
 *   { id: undefined, data: {...} }   // Invalid
 * ];
 * const validDestinations = destinations.filter(hasValidDestinationData);
 * // Returns: 1 destination (first one)
 * ```
 */
export function hasValidDestinationData(
  destination: EntityContainer<DestinationDTO>,
): destination is EntityContainer<DestinationDTO> & {
  id: number;
  data: NonNullable<DestinationDTO>;
} {
  return (
    typeof destination.id === 'number' &&
    destination.data !== null &&
    destination.data !== undefined
  );
}

/**
 * Calculates the total loyalty points required for a shopping cart.
 *
 * @remarks
 * Pure calculation function that sums up all loyalty point values from shopping cart items,
 * accounting for item quantities. Returns 0 if the cart has no items or if items is undefined/null.
 * Safely handles missing loyalty data by treating missing values as 0 points.
 * Treats missing quantities as 1 (default quantity).
 *
 * Used in reward shopping cart components to:
 * - Calculate total points required for checkout
 * - Validate if customer has sufficient points
 * - Display remaining points after purchase
 *
 * @param items - Shopping cart items to calculate total points from
 * @returns Total loyalty points required (sum of all item loyalty values × quantities), or 0 if no items
 *
 * @example
 * ```typescript
 * const items = [
 *   { data: { loyalty: { value: 20100 }, quantity: 2 } },  // 20100 × 2 = 40200
 *   { data: { loyalty: { value: 9100 }, quantity: 1 } },   // 9100 × 1 = 9100
 *   { data: { loyalty: null } }                            // 0 points (counted as 0)
 * ];
 * const total = calculateTotalLoyaltyPoints(items);
 * // Returns: 49300
 * ```
 *
 * @example
 * ```typescript
 * const emptyCart = [];
 * const total = calculateTotalLoyaltyPoints(emptyCart);
 * // Returns: 0
 * ```
 */
export function calculateTotalLoyaltyPoints(
  items: EntityDTOContainerOfShoppingCartItemDTO[] | undefined,
): number {
  if (!items?.length) {
    return 0;
  }
  return items.reduce((sum, item) => {
    const loyaltyValue = item.data?.loyalty?.value ?? 0;
    const quantity = item.data?.quantity ?? 1;
    return sum + loyaltyValue * quantity;
  }, 0);
}
