import { describe, it, expect } from 'vitest';
import {
  filterShippingItems,
  filterDeliveryDestinations,
  hasValidItemId,
  hasValidDestinationData,
  ShippingTargets,
  calculateTotalLoyaltyPoints,
} from './checkout-data.helpers';
import {
  EntityDTOContainerOfShoppingCartItemDTO,
  DestinationDTO,
} from '@generated/swagger/checkout-api';
import { EntityContainer } from '@isa/common/data-access';

describe('Checkout Data Helpers', () => {
  describe('filterShippingItems', () => {
    it('should filter DIG-Versand items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'DIG-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(1);
    });

    it('should filter B2B-Versand items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'B2B-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'Abholung' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(1);
    });

    it('should filter both DIG-Versand and B2B-Versand items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'DIG-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'B2B-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 3,
          data: {
            features: { orderType: 'Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(2);
      expect(result[0].id).toBe(1);
      expect(result[1].id).toBe(2);
    });

    it('should exclude standard delivery items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should exclude pickup items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'Abholung' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should exclude take away items', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'Rücklage' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should return empty array when no shipping items present', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: { orderType: 'Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'Abholung' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should return empty array for empty input', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should handle items with null/undefined data', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: null,
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'DIG-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(2);
    });

    it('should handle items with null/undefined features', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            features: null,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            features: { orderType: 'B2B-Versand' },
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = filterShippingItems(items);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(2);
    });
  });

  describe('filterDeliveryDestinations', () => {
    it('should filter standard delivery destinations (target 2)', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: { target: 2 } as DestinationDTO,
        },
        {
          id: 2,
          data: { target: 1 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(1);
      expect(result[0].data?.target).toBe(ShippingTargets.STANDARD_DELIVERY);
    });

    it('should filter B2B delivery destinations (target 16)', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: { target: 16 } as DestinationDTO,
        },
        {
          id: 2,
          data: { target: 1 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(1);
      expect(result[0].data?.target).toBe(ShippingTargets.B2B_DELIVERY);
    });

    it('should filter both standard and B2B delivery destinations', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: { target: 2 } as DestinationDTO,
        },
        {
          id: 2,
          data: { target: 16 } as DestinationDTO,
        },
        {
          id: 3,
          data: { target: 1 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(2);
      expect(result[0].data?.target).toBe(2);
      expect(result[1].data?.target).toBe(16);
    });

    it('should exclude pickup destinations', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: { target: 1 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should return empty array for empty input', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(0);
    });

    it('should handle destinations with null/undefined data', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: null as unknown as DestinationDTO,
        },
        {
          id: 2,
          data: { target: 2 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(2);
    });

    it('should handle destinations with undefined target', () => {
      // Arrange
      const destinations: EntityContainer<DestinationDTO>[] = [
        {
          id: 1,
          data: {} as DestinationDTO,
        },
        {
          id: 2,
          data: { target: 16 } as DestinationDTO,
        },
      ];

      // Act
      const result = filterDeliveryDestinations(destinations);

      // Assert
      expect(result).toHaveLength(1);
      expect(result[0].id).toBe(2);
    });
  });

  describe('hasValidItemId', () => {
    it('should return true for items with valid id and product', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 1,
        data: {
          product: { id: 42 },
        },
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(true);
    });

    it('should return false for items with undefined id', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: undefined,
        data: {
          product: { id: 42 },
        },
      } as unknown as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for items with null id', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: null,
        data: {
          product: { id: 42 },
        },
      } as unknown as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for items with null data', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 1,
        data: null,
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for items with undefined data', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 1,
        data: undefined,
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for items with null product', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 1,
        data: {
          product: null,
        },
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for items with undefined product', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 1,
        data: {
          product: undefined,
        },
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(false);
    });

    it('should return true for items with zero id (valid edge case)', () => {
      // Arrange
      const item: EntityDTOContainerOfShoppingCartItemDTO = {
        id: 0,
        data: {
          product: { id: 42 },
        },
      } as EntityDTOContainerOfShoppingCartItemDTO;

      // Act
      const result = hasValidItemId(item);

      // Assert
      expect(result).toBe(true);
    });
  });

  describe('hasValidDestinationData', () => {
    it('should return true for destinations with valid id and data', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: 1,
        data: { target: 2 } as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(true);
    });

    it('should return false for destinations with undefined id', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: undefined as unknown as number,
        data: { target: 2 } as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for destinations with null id', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: null as unknown as number,
        data: { target: 2 } as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for destinations with null data', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: 1,
        data: null as unknown as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(false);
    });

    it('should return false for destinations with undefined data', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: 1,
        data: undefined,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(false);
    });

    it('should return true for destinations with zero id (valid edge case)', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: 0,
        data: { target: 2 } as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(true);
    });

    it('should accept destinations with empty data object', () => {
      // Arrange
      const destination: EntityContainer<DestinationDTO> = {
        id: 1,
        data: {} as DestinationDTO,
      };

      // Act
      const result = hasValidDestinationData(destination);

      // Assert
      expect(result).toBe(true);
    });
  });

  describe('ShippingTargets constants', () => {
    it('should have correct STANDARD_DELIVERY value', () => {
      expect(ShippingTargets.STANDARD_DELIVERY).toBe(2);
    });

    it('should have correct B2B_DELIVERY value', () => {
      expect(ShippingTargets.B2B_DELIVERY).toBe(16);
    });
  });

  describe('calculateTotalLoyaltyPoints', () => {
    it('should calculate total loyalty points with quantities', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: { value: 18500 },
            quantity: 1,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 20100 },
            quantity: 2,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 18500 × 1 + 20100 × 2 = 18500 + 40200 = 58700
      expect(result).toBe(58700);
    });

    it('should return 0 for empty array', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      expect(result).toBe(0);
    });

    it('should return 0 for undefined items', () => {
      // Arrange
      const items = undefined;

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      expect(result).toBe(0);
    });

    it('should handle items without loyalty points', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: null,
            quantity: 2,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 10000 },
            quantity: 1,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 0 × 2 + 10000 × 1 = 10000
      expect(result).toBe(10000);
    });

    it('should treat missing quantity as 1', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: { value: 15000 },
            quantity: undefined,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 15000 × 1 (default) = 15000
      expect(result).toBe(15000);
    });

    it('should handle items with zero loyalty points', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: { value: 0 },
            quantity: 5,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 12000 },
            quantity: 1,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 0 × 5 + 12000 × 1 = 12000
      expect(result).toBe(12000);
    });

    it('should handle items with null data', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: null,
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 8000 },
            quantity: 2,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 0 + 8000 × 2 = 16000
      expect(result).toBe(16000);
    });

    it('should handle multiple items with different quantities', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: { value: 5000 },
            quantity: 3,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 10000 },
            quantity: 1,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 3,
          data: {
            loyalty: { value: 2500 },
            quantity: 4,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 5000 × 3 + 10000 × 1 + 2500 × 4 = 15000 + 10000 + 10000 = 35000
      expect(result).toBe(35000);
    });

    it('should handle items with zero quantity', () => {
      // Arrange
      const items: EntityDTOContainerOfShoppingCartItemDTO[] = [
        {
          id: 1,
          data: {
            loyalty: { value: 20000 },
            quantity: 0,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
        {
          id: 2,
          data: {
            loyalty: { value: 10000 },
            quantity: 2,
          },
        } as EntityDTOContainerOfShoppingCartItemDTO,
      ];

      // Act
      const result = calculateTotalLoyaltyPoints(items);

      // Assert
      // 20000 × 0 + 10000 × 2 = 0 + 20000 = 20000
      expect(result).toBe(20000);
    });
  });
});
