import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { OrderRewardCollectService } from './order-reward-collect.service';
import {
  OrderService,
  DBHOrderItemListItemDTO,
} from '@generated/swagger/oms-api';
import { of } from 'rxjs';

describe('OrderRewardCollectService', () => {
  let spectator: SpectatorService<OrderRewardCollectService>;
  const createService = createServiceFactory({
    service: OrderRewardCollectService,
    mocks: [OrderService],
  });

  beforeEach(() => {
    spectator = createService();
  });

  it('should be created', () => {
    expect(spectator.service).toBeTruthy();
  });

  describe('collect', () => {
    it('should collect reward item successfully', async () => {
      // Arrange
      const mockParams = {
        orderId: 123,
        orderItemId: 456,
        orderItemSubsetId: 789,
        collectType: 1 as const, // Valid LoyaltyCollectType.Collect
        quantity: 2,
      };
      const mockResult: DBHOrderItemListItemDTO[] = [
        { orderItemType: 1 } as DBHOrderItemListItemDTO,
      ];
      const mockResponse = { result: mockResult, error: false };
      const orderService = spectator.inject(OrderService);
      orderService.OrderLoyaltyCollect.mockReturnValue(of(mockResponse));

      // Act
      const result = await spectator.service.collect(mockParams);

      // Assert
      expect(result).toEqual(mockResult);
      expect(orderService.OrderLoyaltyCollect).toHaveBeenCalledWith({
        orderId: mockParams.orderId,
        orderItemId: mockParams.orderItemId,
        orderItemSubsetId: mockParams.orderItemSubsetId,
        data: {
          collectType: mockParams.collectType,
          quantity: mockParams.quantity,
        },
      });
      expect(orderService.OrderLoyaltyCollect).toHaveBeenCalledTimes(1);
    });

    it('should throw error if API response contains error', async () => {
      // Arrange
      const mockParams = {
        orderId: 123,
        orderItemId: 456,
        orderItemSubsetId: 789,
        collectType: 1 as const, // Valid LoyaltyCollectType.Collect
        quantity: 2,
      };
      const mockResponse = { error: true, result: undefined };
      const orderService = spectator.inject(OrderService);
      orderService.OrderLoyaltyCollect.mockReturnValue(of(mockResponse));

      // Act & Assert
      await expect(spectator.service.collect(mockParams)).rejects.toThrow();
      expect(orderService.OrderLoyaltyCollect).toHaveBeenCalledWith({
        orderId: mockParams.orderId,
        orderItemId: mockParams.orderItemId,
        orderItemSubsetId: mockParams.orderItemSubsetId,
        data: {
          collectType: mockParams.collectType,
          quantity: mockParams.quantity,
        },
      });
    });
  });

  describe('fetchOrderItemSubset', () => {
    it('should fetch order item subset successfully', async () => {
      // Arrange
      const mockParams = {
        orderItemSubsetId: 789,
      };
      const mockResult = {
        id: 789,
        quantity: 2,
        name: 'Test Subset',
      };
      const mockResponse = { result: mockResult, error: false };
      const orderService = spectator.inject(OrderService);
      orderService.OrderGetOrderItemSubset.mockReturnValue(of(mockResponse));

      // Act
      const result = await spectator.service.fetchOrderItemSubset(mockParams);

      // Assert
      expect(result).toEqual(mockResult);
      expect(orderService.OrderGetOrderItemSubset).toHaveBeenCalledWith(
        mockParams.orderItemSubsetId,
      );
      expect(orderService.OrderGetOrderItemSubset).toHaveBeenCalledTimes(1);
    });
  });
});
