import { DisplayOrder, DisplayOrderItem } from '@isa/oms/data-access';
import { OrderTypeFeature } from '../models';

/**
 * Represents a group of orders sharing the same branch (for pickup/in-store)
 * or all orders for delivery types that don't have branch-specific grouping.
 */
export type OrderBranchGroup = {
  /** Branch ID (undefined for delivery types without branch grouping) */
  branchId?: number;
  /** Branch name (undefined for delivery types without branch grouping) */
  branchName?: string;
  /** Array of orders in this branch group */
  orders: DisplayOrder[];
  /** Flattened array of all items from all orders in this group */
  allItems: DisplayOrderItem[];
};

/**
 * Order types that require grouping by branch/filiale.
 * Other order types (Versand, DIG-Versand, etc.) are grouped together without branch subdivision.
 */
const ORDER_TYPES_WITH_BRANCH_GROUPING = [
  OrderTypeFeature.Pickup,
  OrderTypeFeature.InStore,
] as const;

/**
 * Sorts orders by branch ID (ascending).
 */
const sortByBranchId = (
  entries: [number, DisplayOrder[]][],
): [number, DisplayOrder[]][] => {
  return [...entries].sort(([a], [b]) => a - b);
};

/**
 * Groups display orders by their target branch.
 * Only applies branch-level grouping for Abholung (Pickup) and Rücklage (InStore) order types.
 * For other delivery types (Versand, DIG-Versand, etc.), returns a single group with all orders.
 *
 * @param orderType - The order type to determine if branch grouping is needed
 * @param orders - Array of DisplayOrder objects to group
 * @returns Array of OrderBranchGroup objects, each containing orders and items for a specific branch
 *
 * @example
 * ```typescript
 * // For Abholung (pickup) orders
 * const pickupOrders = [
 *   { targetBranch: { id: 1, name: 'München' }, items: [item1, item2] },
 *   { targetBranch: { id: 2, name: 'Berlin' }, items: [item3] }
 * ];
 * const groups = groupDisplayOrdersByBranch('Abholung', pickupOrders);
 * // [
 * //   { branchId: 1, branchName: 'München', orders: [...], allItems: [item1, item2] },
 * //   { branchId: 2, branchName: 'Berlin', orders: [...], allItems: [item3] }
 * // ]
 *
 * // For Versand (delivery) orders
 * const deliveryOrders = [
 *   { items: [item1] },
 *   { items: [item2, item3] }
 * ];
 * const groups = groupDisplayOrdersByBranch('Versand', deliveryOrders);
 * // [
 * //   { branchId: undefined, branchName: undefined, orders: [...], allItems: [item1, item2, item3] }
 * // ]
 * ```
 */
export function groupDisplayOrdersByBranch(
  orderType: OrderTypeFeature | string,
  orders: DisplayOrder[],
): OrderBranchGroup[] {
  const needsBranchGrouping =
    orderType === OrderTypeFeature.Pickup ||
    orderType === OrderTypeFeature.InStore;

  if (!needsBranchGrouping) {
    // For delivery types without branch grouping, return single group with all orders
    const allItems = orders.flatMap((order) => order.items ?? []);
    return [
      {
        branchId: undefined,
        branchName: undefined,
        orders,
        allItems,
      },
    ];
  }

  // For Abholung/Rücklage, group by targetBranch.id
  const branchGroups = orders.reduce((map, order) => {
    const branchId = order.targetBranch?.id ?? 0;
    if (!map.has(branchId)) {
      map.set(branchId, []);
    }
    map.get(branchId)!.push(order);
    return map;
  }, new Map<number, DisplayOrder[]>());

  // Convert Map to array of OrderBranchGroup, sorted by branch ID
  return sortByBranchId(Array.from(branchGroups.entries())).map(
    ([branchId, branchOrders]) => {
      const branch = branchOrders[0]?.targetBranch;
      const allItems = branchOrders.flatMap((order) => order.items ?? []);

      return {
        branchId: branchId || undefined,
        branchName: branch?.name,
        orders: branchOrders,
        allItems,
      };
    },
  );
}
