import { describe, it, expect, beforeEach, vi } from 'vitest';
import { TestBed } from '@angular/core/testing';
import { HttpErrorResponse } from '@angular/common/http';
import { of } from 'rxjs';
import { CheckoutService } from './checkout.service';
import { ShoppingCartService } from './shopping-cart.service';
import {
  StoreCheckoutService,
  StoreCheckoutShoppingCartService,
  StoreCheckoutBuyerService,
  StoreCheckoutPayerService,
  StoreCheckoutPaymentService,
} from '@generated/swagger/checkout-api';
import { OrderCreationService } from '@isa/oms/data-access';
import { AvailabilityService } from '@isa/availability/data-access';
import { CheckoutCompletionError } from '../errors';
import { CompleteCheckoutParams } from '../schemas';
import {
  ShoppingCart,
  ShoppingCartItem,
  Order,
  Buyer,
  Payer,
  ShippingAddress,
  Destination,
  Checkout,
} from '../models';
import { EntityContainer } from '@isa/common/data-access';
import { LogLevel, provideLogging } from '@isa/core/logging';

describe('CheckoutService', () => {
  let service: CheckoutService;
  let mockShoppingCartDataService: any;
  let mockStoreCheckoutService: any;
  let mockOrderCreationService: any;
  let mockStoreCheckoutShoppingCartService: any;
  let mockBuyerService: any;
  let mockPayerService: any;
  let mockPaymentService: any;
  let mockAvailabilityService: any;

  // Test fixtures
  const createMockShoppingCartItem = (
    orderType: string,
  ): EntityContainer<ShoppingCartItem> => {
    const item: EntityContainer<ShoppingCartItem> = {
      id: Math.floor(Math.random() * 1000),
      data: {
        product: {
          name: 'Test Product',
          ean: '1234567890123',
        },
        features: { orderType },
        loyalty: {
          value: 0,
        },
        campaign: {
          value: 0,
        },
        promotion: {
          value: 0,
        },
        availability: {
          availabilityType: 1,
          inStock: 5,
        },
        destination: {
          id: Math.floor(Math.random() * 1000),
          data: {
            target: 1,
          },
        },
        quantity: 1,
      },
    };
    return item;
  };

  const createMockShoppingCart = (
    items: EntityContainer<ShoppingCartItem>[],
  ): ShoppingCart => {
    const cart: ShoppingCart = {
      id: 456,
      items,
      total: {
        value: 100,
        currency: 'EUR',
        currencySymbol: '€',
      },
    };
    return cart;
  };

  const createMockCheckout = (): Checkout =>
    ({
      id: 123,
      destinations: [
        {
          id: 1,
          data: {
            target: 2, // Delivery
          } as Destination,
        },
      ],
    }) as Checkout;

  const createMockOrders = (): Order[] => [
    {
      id: 789,
      orderNumber: 'ORD-123',
    } as Order,
  ];

  const createValidParams = (
    overrides?: Partial<CompleteCheckoutParams>,
  ): CompleteCheckoutParams => ({
    shoppingCartId: 456,
    buyer: {
      id: 1,
      firstName: 'John',
      lastName: 'Doe',
      buyerType: 0, // Valid literal value
    } as Buyer,
    notificationChannels: 1,
    customerFeatures: { webshop: 'true' },
    ...overrides,
  });

  beforeEach(() => {
    // Create mocks
    mockShoppingCartDataService = {
      getShoppingCart: vi.fn(),
    };

    mockStoreCheckoutService = {
      StoreCheckoutCreateOrRefreshCheckout: vi.fn(),
      StoreCheckoutSetNotificationChannels: vi.fn(),
      StoreCheckoutUpdateDestination: vi.fn(),
    };

    mockOrderCreationService = {
      createOrdersFromCheckout: vi.fn(),
      getLogistician: vi.fn(),
    };

    mockStoreCheckoutShoppingCartService = {
      StoreCheckoutShoppingCartUpdateShoppingCartItem: vi.fn(),
      StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer: vi.fn(),
      StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability: vi.fn(),
    };

    mockBuyerService = {
      StoreCheckoutBuyerSetBuyerPOST: vi.fn(),
    };

    mockPayerService = {
      StoreCheckoutPayerSetPayerPOST: vi.fn(),
    };

    mockPaymentService = {
      StoreCheckoutPaymentSetPaymentType: vi.fn(),
    };

    mockAvailabilityService = {
      getAvailabilities: vi.fn(),
      getAvailability: vi.fn(),
    };

    // Configure TestBed
    TestBed.configureTestingModule({
      providers: [
        CheckoutService,
        { provide: ShoppingCartService, useValue: mockShoppingCartDataService },
        { provide: StoreCheckoutService, useValue: mockStoreCheckoutService },
        { provide: OrderCreationService, useValue: mockOrderCreationService },
        {
          provide: StoreCheckoutShoppingCartService,
          useValue: mockStoreCheckoutShoppingCartService,
        },
        { provide: StoreCheckoutBuyerService, useValue: mockBuyerService },
        { provide: StoreCheckoutPayerService, useValue: mockPayerService },
        { provide: StoreCheckoutPaymentService, useValue: mockPaymentService },
        { provide: AvailabilityService, useValue: mockAvailabilityService },
        provideLogging({ level: LogLevel.Off }),
      ],
    });

    service = TestBed.inject(CheckoutService);
  });

  describe('complete', () => {
    it('should successfully complete checkout with pickup items (Bar payment)', async () => {
      // Arrange
      const params = createValidParams();
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Abholung'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );

      // Act
      const result = await service.complete(params);

      // Assert
      expect(result).toEqual(checkout.id);
      expect(
        mockPaymentService.StoreCheckoutPaymentSetPaymentType,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        paymentType: 4, // Bar payment for pickup
      });
      expect(
        mockPayerService.StoreCheckoutPayerSetPayerPOST,
      ).not.toHaveBeenCalled();
    });

    it('should use Rechnung payment for delivery orders', async () => {
      // Arrange
      const params = createValidParams({
        payer: {
          id: 2,
          firstName: 'Jane',
          lastName: 'Smith',
          payerType: 0,
        } as Payer,
        shippingAddress: { firstName: 'John' } as ShippingAddress,
      });
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Versand'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer.mockReturnValue(
        of({ result: {}, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability.mockReturnValue(
        of({ result: shoppingCart, error: null }),
      );
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPayerService.StoreCheckoutPayerSetPayerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutUpdateDestination.mockReturnValue(
        of({ result: {}, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockResolvedValue(
        orders,
      );

      // Act
      const result = await service.complete(params);

      // Assert
      expect(
        mockPaymentService.StoreCheckoutPaymentSetPaymentType,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        paymentType: 128, // Rechnung for delivery
      });
      expect(
        mockPayerService.StoreCheckoutPayerSetPayerPOST,
      ).toHaveBeenCalled();
    });

    it('should set payer for B2B customers even with pickup items', async () => {
      // Arrange
      const params = createValidParams({
        customerFeatures: { b2b: 'true' },
        payer: {
          reference: { id: 2 },
          source: 2,
          payerType: 0,
        } as Payer,
      });
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Abholung'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPayerService.StoreCheckoutPayerSetPayerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );

      // Act
      await service.complete(params);

      // Assert
      expect(
        mockPayerService.StoreCheckoutPayerSetPayerPOST,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        payerDTO: params.payer,
      });
    });

    it('should apply special comment to all items', async () => {
      // Arrange
      const params = createValidParams({
        specialComment: 'Rush delivery needed',
      });
      const items = [
        createMockShoppingCartItem('Abholung'),
        createMockShoppingCartItem('Abholung'),
      ];
      const shoppingCart = createMockShoppingCart(items);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem.mockReturnValue(
        of({ result: shoppingCart, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockResolvedValue(
        orders,
      );

      // Act
      await service.complete(params);

      // Assert
      expect(
        mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem,
      ).toHaveBeenCalledTimes(2);
      expect(
        mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItem,
      ).toHaveBeenCalledWith({
        shoppingCartId: 456,
        shoppingCartItemId: expect.any(Number),
        values: { specialComment: 'Rush delivery needed' },
      });
    });

    it('should update shipping addresses on delivery destinations', async () => {
      // Arrange
      const shippingAddress = {
        firstName: 'John',
        lastName: 'Doe',
      } as ShippingAddress;
      const params = createValidParams({
        payer: { id: 2, payerType: 0 } as Payer,
        shippingAddress,
      });
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Versand'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer.mockReturnValue(
        of({ result: {}, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability.mockReturnValue(
        of({ result: shoppingCart, error: null }),
      );
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPayerService.StoreCheckoutPayerSetPayerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutUpdateDestination.mockReturnValue(
        of({ result: {}, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockResolvedValue(
        orders,
      );

      // Act
      await service.complete(params);

      // Assert
      expect(
        mockStoreCheckoutService.StoreCheckoutUpdateDestination,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        destinationId: 1,
        destinationDTO: expect.objectContaining({
          shippingAddress,
        }),
      });
    });

    it('should throw error when shopping cart is empty', async () => {
      // Arrange
      const params = createValidParams();
      const emptyCart = createMockShoppingCart([]);

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(emptyCart);

      // Act & Assert
      await expect(service.complete(params)).rejects.toThrow(
        CheckoutCompletionError,
      );
      await expect(service.complete(params)).rejects.toThrow(/empty/i);
    });

    it('should throw error when payer is missing for delivery orders', async () => {
      // Arrange
      const params = createValidParams(); // No payer
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Versand'),
      ]);

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );

      // Act & Assert
      await expect(service.complete(params)).rejects.toThrow(
        CheckoutCompletionError,
      );
      await expect(service.complete(params)).rejects.toThrow(/payer/i);
    });

    it.skip('should handle HTTP 409 conflict error', async () => {
      // Arrange
      const params = createValidParams();
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Abholung'),
      ]);
      const checkout = createMockCheckout();
      const existingOrders = createMockOrders();

      const conflictError = new HttpErrorResponse({
        status: 409,
        error: { result: existingOrders },
      });

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockRejectedValue(
        conflictError,
      );

      // Act & Assert
      await expect(service.complete(params)).rejects.toThrow(
        CheckoutCompletionError,
      );
      await expect(service.complete(params)).rejects.toMatchObject({
        code: 'CHECKOUT_CONFLICT',
        details: expect.objectContaining({
          existingOrders,
        }),
      });
    });

    it('should support cancellation via AbortSignal', async () => {
      // Arrange
      const abortController = new AbortController();
      const params = createValidParams();
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Abholung'),
      ]);

      mockShoppingCartDataService.getShoppingCart.mockImplementation(() => {
        abortController.abort();
        return Promise.reject(new Error('Aborted'));
      });

      // Act & Assert
      await expect(
        service.complete(params, abortController.signal),
      ).rejects.toThrow();
    });

    it('should handle download orders with Rechnung payment', async () => {
      // Arrange
      const params = createValidParams({
        payer: { id: 2, payerType: 0 } as Payer,
      });
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Download'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer.mockReturnValue(
        of({ result: {}, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability.mockReturnValue(
        of({ result: shoppingCart, error: null }),
      );
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPayerService.StoreCheckoutPayerSetPayerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockResolvedValue(
        orders,
      );

      // Act
      await service.complete(params);

      // Assert
      expect(
        mockPaymentService.StoreCheckoutPaymentSetPaymentType,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        paymentType: 128, // Rechnung for download
      });
      expect(
        mockPayerService.StoreCheckoutPayerSetPayerPOST,
      ).toHaveBeenCalled();
    });

    it('should handle mixed order types correctly', async () => {
      // Arrange
      const params = createValidParams({
        payer: { id: 2, payerType: 0 } as Payer,
        shippingAddress: { firstName: 'John' } as ShippingAddress,
      });
      const shoppingCart = createMockShoppingCart([
        createMockShoppingCartItem('Abholung'),
        createMockShoppingCartItem('Versand'),
        createMockShoppingCartItem('Download'),
      ]);
      const checkout = createMockCheckout();
      const orders = createMockOrders();

      mockShoppingCartDataService.getShoppingCart.mockResolvedValue(
        shoppingCart,
      );
      mockStoreCheckoutService.StoreCheckoutCreateOrRefreshCheckout.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartSetLogisticianOnDestinationsByBuyer.mockReturnValue(
        of({ result: {}, error: null }),
      );
      // Mock availability response with available status (code 1024 = Available)
      mockAvailabilityService.getAvailabilities.mockImplementation((params) => {
        const result: Record<string, any> = {};
        if (params.items) {
          params.items.forEach((item: any) => {
            result[item.itemId.toString()] = {
              status: 1024, // Available status code
              ssc: '1024',
              sscText: 'Available',
              supplierId: 1,
              at: '2024-01-01',
              requested: new Date().toISOString(),
              isPrebooked: false,
            };
          });
        }
        return Promise.resolve(result);
      });
      mockStoreCheckoutShoppingCartService.StoreCheckoutShoppingCartUpdateShoppingCartItemAvailability.mockReturnValue(
        of({ result: shoppingCart, error: null }),
      );
      mockBuyerService.StoreCheckoutBuyerSetBuyerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPayerService.StoreCheckoutPayerSetPayerPOST.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutSetNotificationChannels.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockPaymentService.StoreCheckoutPaymentSetPaymentType.mockReturnValue(
        of({ result: checkout, error: null }),
      );
      mockStoreCheckoutService.StoreCheckoutUpdateDestination.mockReturnValue(
        of({ result: {}, error: null }),
      );
      mockOrderCreationService.createOrdersFromCheckout.mockResolvedValue(
        orders,
      );

      // Act
      await service.complete(params);

      // Assert
      expect(
        mockPaymentService.StoreCheckoutPaymentSetPaymentType,
      ).toHaveBeenCalledWith({
        checkoutId: 123,
        paymentType: 128, // Rechnung because delivery and download are present
      });
      expect(
        mockPayerService.StoreCheckoutPayerSetPayerPOST,
      ).toHaveBeenCalled();
    });
  });
});
