import { describe, it, expect } from 'vitest';
import {
  groupItemsByDeliveryDestination,
  SHIPPING_ORDER_TYPE_FEATURES,
  BRANCH_ORDER_TYPE_FEATURES,
} from './group-items-by-delivery-destination.helper';
import {
  DisplayOrderDTO,
  DisplayOrderItemDTO,
  BranchDTO,
  DisplayAddresseeDTO,
} from '@generated/swagger/oms-api';
import { OrderTypeFeature } from '@isa/common/data-access';

describe('groupItemsByDeliveryDestination', () => {
  it('should return empty array when orders array is empty', () => {
    const result = groupItemsByDeliveryDestination([]);
    expect(result).toHaveLength(0);
  });

  it('should return empty array when orders is undefined', () => {
    const result = groupItemsByDeliveryDestination(undefined);
    expect(result).toHaveLength(0);
  });

  it('should return empty array when orders is null', () => {
    const result = groupItemsByDeliveryDestination(null);
    expect(result).toHaveLength(0);
  });

  it('should skip orders without items', () => {
    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [],
        features: { orderType: OrderTypeFeature.Delivery },
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);
    expect(result).toHaveLength(0);
  });

  it('should skip items without valid order type', () => {
    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          { id: 'item1', features: {} } as DisplayOrderItemDTO,
        ],
        features: {},
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);
    expect(result).toHaveLength(0);
  });

  it('should group single order with single item', () => {
    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Delivery },
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(1);
    expect(result[0].orderType).toBe(OrderTypeFeature.Delivery);
    expect(result[0].orderTypeIcon).toBe('isaDeliveryVersand');
    expect(result[0].items).toHaveLength(1);
    expect(result[0].items[0].id).toBe('item1');
  });

  it('should group items by shipping address for delivery orders', () => {
    const address1: DisplayAddresseeDTO = {
      firstName: 'John',
      lastName: 'Doe',
      gender: 0,
      address: {
        street: 'Main Street',
        streetNumber: '123',
        city: 'Berlin',
        zipCode: '10115',
      },
    } as DisplayAddresseeDTO;

    const address2: DisplayAddresseeDTO = {
      firstName: 'Jane',
      lastName: 'Smith',
      gender: 0,
      address: {
        street: 'Second Street',
        streetNumber: '456',
        city: 'Munich',
        zipCode: '80331',
      },
    } as DisplayAddresseeDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
          {
            id: 'item2',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Delivery },
        shippingAddress: address1,
      } as DisplayOrderDTO,
      {
        id: '2',
        items: [
          {
            id: 'item3',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Delivery },
        shippingAddress: address2,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(2);

    const group1 = result.find(
      (g) => g.shippingAddress?.firstName === 'John' && g.shippingAddress?.lastName === 'Doe',
    );
    expect(group1).toBeDefined();
    expect(group1!.items).toHaveLength(2);
    expect(group1!.orderType).toBe(OrderTypeFeature.Delivery);
    expect(group1!.shippingAddress).toEqual(address1);

    const group2 = result.find(
      (g) => g.shippingAddress?.firstName === 'Jane' && g.shippingAddress?.lastName === 'Smith',
    );
    expect(group2).toBeDefined();
    expect(group2!.items).toHaveLength(1);
    expect(group2!.orderType).toBe(OrderTypeFeature.Delivery);
    expect(group2!.shippingAddress).toEqual(address2);
  });

  it('should group items by target branch for pickup orders', () => {
    const branch1: BranchDTO = {
      id: 'branch1',
      name: 'Branch 1',
    } as BranchDTO;

    const branch2: BranchDTO = {
      id: 'branch2',
      name: 'Branch 2',
    } as BranchDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Pickup },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Pickup },
        targetBranch: branch1,
      } as DisplayOrderDTO,
      {
        id: '2',
        items: [
          {
            id: 'item2',
            features: { orderType: OrderTypeFeature.Pickup },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Pickup },
        targetBranch: branch2,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(2);

    const group1 = result.find((g) => g.targetBranch?.id === 'branch1');
    expect(group1).toBeDefined();
    expect(group1!.items).toHaveLength(1);
    expect(group1!.orderType).toBe(OrderTypeFeature.Pickup);

    const group2 = result.find((g) => g.targetBranch?.id === 'branch2');
    expect(group2).toBeDefined();
    expect(group2!.items).toHaveLength(1);
    expect(group2!.orderType).toBe(OrderTypeFeature.Pickup);
  });

  it('should group multiple items with same destination together', () => {
    const branch1: BranchDTO = {
      id: 'branch1',
      name: 'Branch 1',
    } as BranchDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Pickup },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Pickup },
        targetBranch: branch1,
      } as DisplayOrderDTO,
      {
        id: '2',
        items: [
          {
            id: 'item2',
            features: { orderType: OrderTypeFeature.Pickup },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Pickup },
        targetBranch: branch1,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(1);
    expect(result[0].items).toHaveLength(2);
    expect(result[0].targetBranch?.id).toBe('branch1');
    expect(result[0].orderType).toBe(OrderTypeFeature.Pickup);
  });

  it('should handle mixed order types in different orders', () => {
    const branch1: BranchDTO = {
      id: 'branch1',
      name: 'Branch 1',
    } as BranchDTO;

    const address1: DisplayAddresseeDTO = {
      firstName: 'Alice',
      lastName: 'Johnson',
      gender: 0,
      address: {
        street: 'Oak Street',
        streetNumber: '789',
        city: 'Hamburg',
        zipCode: '20095',
      },
    } as DisplayAddresseeDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Pickup },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Pickup },
        targetBranch: branch1,
      } as DisplayOrderDTO,
      {
        id: '2',
        items: [
          {
            id: 'item2',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Delivery },
        shippingAddress: address1,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(2);

    const pickupGroup = result.find(
      (g) => g.orderType === OrderTypeFeature.Pickup,
    );
    expect(pickupGroup).toBeDefined();
    expect(pickupGroup!.targetBranch?.id).toBe('branch1');

    const deliveryGroup = result.find(
      (g) => g.orderType === OrderTypeFeature.Delivery,
    );
    expect(deliveryGroup).toBeDefined();
    expect(deliveryGroup!.shippingAddress).toEqual(address1);
  });

  it('should include order features in the group', () => {
    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.Delivery },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.Delivery, customFeature: 'value' },
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(1);
    expect(result[0].features).toEqual({
      orderType: OrderTypeFeature.Delivery,
      customFeature: 'value',
    });
  });

  it('should handle B2BShipping as shipping order type', () => {
    const address1: DisplayAddresseeDTO = {
      firstName: 'Bob',
      lastName: 'Williams',
      gender: 0,
      address: {
        street: 'Business Ave',
        streetNumber: '100',
        city: 'Frankfurt',
        zipCode: '60311',
      },
    } as DisplayAddresseeDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.B2BShipping },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.B2BShipping },
        shippingAddress: address1,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(1);
    expect(result[0].orderType).toBe(OrderTypeFeature.B2BShipping);
    expect(result[0].orderTypeIcon).toBe('isaDeliveryB2BVersand1');
    expect(result[0].shippingAddress).toEqual(address1);
  });

  it('should handle InStore as branch order type', () => {
    const branch1: BranchDTO = {
      id: 'branch1',
      name: 'Branch 1',
    } as BranchDTO;

    const orders: DisplayOrderDTO[] = [
      {
        id: '1',
        items: [
          {
            id: 'item1',
            features: { orderType: OrderTypeFeature.InStore },
          } as DisplayOrderItemDTO,
        ],
        features: { orderType: OrderTypeFeature.InStore },
        targetBranch: branch1,
      } as DisplayOrderDTO,
    ];

    const result = groupItemsByDeliveryDestination(orders);

    expect(result).toHaveLength(1);
    expect(result[0].orderType).toBe(OrderTypeFeature.InStore);
    expect(result[0].orderTypeIcon).toBe('isaDeliveryRuecklage1');
    expect(result[0].targetBranch?.id).toBe('branch1');
  });
});

describe('SHIPPING_ORDER_TYPE_FEATURES', () => {
  it('should contain expected shipping order types', () => {
    expect(SHIPPING_ORDER_TYPE_FEATURES).toContain(OrderTypeFeature.Delivery);
    expect(SHIPPING_ORDER_TYPE_FEATURES).toContain(OrderTypeFeature.B2BShipping);
    expect(SHIPPING_ORDER_TYPE_FEATURES).toContain(OrderTypeFeature.DigitalShipping);
    expect(SHIPPING_ORDER_TYPE_FEATURES).toHaveLength(3);
  });
});

describe('BRANCH_ORDER_TYPE_FEATURES', () => {
  it('should contain expected branch order types', () => {
    expect(BRANCH_ORDER_TYPE_FEATURES).toContain(OrderTypeFeature.Pickup);
    expect(BRANCH_ORDER_TYPE_FEATURES).toContain(OrderTypeFeature.InStore);
    expect(BRANCH_ORDER_TYPE_FEATURES).toHaveLength(2);
  });
});
