import { IJewelleryProductAttr } from '../src/interfaces/product-jewellery-attr.interface';
import { SessionService, LoginUser } from '@tomei/sso';
import { ProductRepository } from '../src/base/product/product.repository';
import { ProductWithInventoryRepository } from '../src/base/product-with-inventory/product-with-inventory.repository';
import { ApplicationConfig } from '@tomei/config';
import { Activity } from '@tomei/activity-history';
import { ProductJewellery } from '../src/components/jewellery-product/jewellery-product';
import { ProductJewelleryRepository } from '../src/components/jewellery-product/jewellery-product.repository';
// import { HashTable } from '@tomei/general';
import { StockProfile } from '@tomei/stock';

describe('JewelleryProduct', () => {
  const data: IJewelleryProductAttr = {
    ProductId: '123',
    Name: 'Test',
    Description: 'Test',
    SKU: 'Test',
    Type: 'Test',
    Remark: 'Test',
    IsTaxableYN: 'N',
    TaxCode: 'Test',
    IsPriceInclusiveTaxYN: 'N',
    Status: 'Active',
    VerifiedYN: 'Y',
    VerifiedById: '123',
    VerifiedAt: new Date(),
    VariantLevels: 0,
    VariantTypeLevel1: '',
    VariantTypeLevel2: '',
    VariantTypeLevel3: '',
    CreatedById: '123',
    CreatedAt: new Date(),
    UpdatedById: '123',
    UpdatedAt: new Date(),
    UpdatedSSYN: 'Y',
    UOM: 'Test',
    TotalUnits: 1,
    TotalUnitsAvailable: 2,
    TotalUnitsInCurrentOrder: 3,
    TotalUnitsSold: 4,
    TotalUnitsReserved: 5,
    TotalUnitsOnConsignment: 6,
    TotalUnitsUnderMaintenance: 7,
    TotalUnitsVoid: 8,
    TotalUnitsInTransit: 9,
    TotalUnitsBackOrdered: 10,
    TotalUnitsPreOrdered: 11,
    StockLowAlertLevel: 12,
    StockReorderLevel: 13,
    BufferStockLevel: 14,
    Surface: 'test',
    Uniqueness: 'test',
    ProfileId: '456',
    HasCertificateYN: 'N',
  };

  const data2 = {
    ProductId: '123',
    Surface: 'test',
    Uniqueness: 'test',
    ProfileId: '456',
    HasCertificateYN: 'N',
    ProductWithInventory: {
      ProductId: '123',
      Name: 'Test',
      Description: 'Test',
      SKU: 'Test',
      Type: 'Test',
      Remark: 'Test',
      IsTaxableYN: 'N',
      TaxCode: 'Test',
      IsPriceInclusiveTaxYN: 'N',
      Status: 'Active',
      VerifiedYN: 'Y',
      VerifiedById: '123',
      VerifiedAt: new Date(),
      VariantLevels: 0,
      VariantTypeLevel1: '',
      VariantTypeLevel2: '',
      VariantTypeLevel3: '',
      CreatedById: '123',
      CreatedAt: new Date(),
      UpdatedById: '123',
      UpdatedAt: new Date(),
      UpdatedSSYN: 'Y',
      UOM: 'Test',
      TotalUnits: 1,
      TotalUnitsAvailable: 2,
      TotalUnitsInCurrentOrder: 3,
      TotalUnitsSold: 4,
      TotalUnitsReserved: 5,
      TotalUnitsOnConsignment: 6,
      TotalUnitsUnderMaintenance: 7,
      TotalUnitsVoid: 8,
      TotalUnitsInTransit: 9,
      TotalUnitsBackOrdered: 10,
      TotalUnitsPreOrdered: 11,
      StockLowAlertLevel: 12,
      StockReorderLevel: 13,
      BufferStockLevel: 14,
      Product: {
        ProductId: '123',
        Name: 'Test',
        Description: 'Test',
        SKU: 'Test',
        Type: 'Test',
        Remark: 'Test',
        IsTaxableYN: 'N',
        TaxCode: 'Test',
        IsPriceInclusiveTaxYN: 'N',
        Status: 'Active',
        VerifiedYN: 'Y',
        VerifiedById: '123',
        VerifiedAt: new Date(),
        VariantLevels: 0,
        VariantTypeLevel1: '',
        VariantTypeLevel2: '',
        VariantTypeLevel3: '',
        CreatedById: '123',
        CreatedAt: new Date(),
        UpdatedById: '123',
        UpdatedAt: new Date(),
        UpdatedSSYN: 'Y',
      },
    },
  };

  const mockStockProfile = new (StockProfile.prototype as any).constructor({
    ProfileId: '123',
    Name: 'test',
    Description: 'test',
    InventoryType: 'test',
    UOM: 'test',
    Category: 'test',
    CategoryType: 'test',
    TotalUnits: 1,
    TotalUnitsAvailable: 1,
    TotalUnitsInCurrentOrder: 1,
    TotalUnitsSold: 1,
    TotalUnitsReserved: 1,
    TotalUnitsOnConsignment: 1,
    TotalUnitsVoid: 1,
    TotalUnitsInTransit: 1,
    TotalUnitsBackOrdered: 1,
    CreatedById: '123',
    CreatedAt: new Date(),
    UpdatedById: '123',
    UpdatedAt: new Date(),
  });

  const pRepoCreate = jest
    .spyOn(ProductRepository.prototype, 'create')
    .mockResolvedValue({
      ...data,
      get: () => data,
    } as any);

  const pwiRepoCreate = jest
    .spyOn(ProductWithInventoryRepository.prototype, 'create')
    .mockResolvedValue({
      ...data,
      get: () => data,
    } as any);

  const jpRepoCreate = jest
    .spyOn(ProductJewelleryRepository.prototype, 'create')
    .mockResolvedValue({
      ...data2,
      get: () => data2,
    } as any);

  jest.spyOn(StockProfile, 'init').mockResolvedValue(mockStockProfile);

  jest.spyOn(ProductRepository.prototype, 'findByPk').mockResolvedValue({
    ...data,
    get: () => data,
  } as any);

  jest
    .spyOn(ProductWithInventoryRepository.prototype, 'findByPk')
    .mockResolvedValue({
      ...data,
      get: () => data,
    } as any);

  /* eslint-disable @typescript-eslint/no-unused-vars */
  const jpfMock = jest
    .spyOn(ProductJewelleryRepository.prototype, 'findOne')
    .mockResolvedValue({
      ...data2,
      get: () => data2,
    } as any);
  /* eslint-enable @typescript-eslint/no-unused-vars */

  jest.spyOn(SessionService, 'init').mockResolvedValue({
    setUserSession: jest.fn(),
    retrieveUserSession: jest.fn(),
    refreshDuration: jest.fn(),
  } as any);

  jest
    .spyOn(ApplicationConfig, 'getComponentConfigValue')
    .mockResolvedValue('ezc' as any);
  jest
    .spyOn(LoginUser.prototype, 'checkPrivileges')
    .mockResolvedValue(true as any);
  const activityMock = jest
    .spyOn(Activity.prototype, 'create')
    .mockResolvedValue(undefined as any);

  jest.spyOn(ProductRepository.prototype, 'findByPk').mockResolvedValue({
    ...data,
    get: () => data,
  } as any);

  // let productTest: ProductJewellery;

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('init', () => {
    it('should be able to create a new jewellery product', async () => {
      const product = await ProductJewellery.init({
        productInfo: data,
      });
      expect(product).toBeDefined();
      expect(product).toBeInstanceOf(ProductJewellery);
    });

    it('should initialize the product base with existing data', async () => {
      const product = await ProductJewellery.init({
        productId: data.ProductId,
      });

      expect(product.ProductId).toBe('123');
      expect(product.Surface).toBe('test');
      expect(product.Uniqueness).toBe('test');
      expect(product.ProfileId).toBe('456');
      expect(product.HasCertificateYN).toBe('N');

      // productTest = product;
    });
  });

  describe('create', () => {
    it('should be able to create a new jewellery product', async () => {
      jest
        .spyOn(ProductRepository.prototype, 'findOne')
        .mockReturnValueOnce(null as any);

      const product = await ProductJewellery.init({
        productId: data.ProductId,
      });

      const sessionService = await SessionService.init();
      const loginUser = await LoginUser.init(sessionService);
      loginUser.ObjectId = '1234567890';
      await product.create(loginUser, {}, data.ProfileId);

      expect(pRepoCreate).toBeCalledTimes(1);
      expect(pwiRepoCreate).toBeCalledTimes(1);
      expect(jpRepoCreate).toBeCalledTimes(1);
      expect(activityMock).toBeCalledTimes(3);
    });

    it('should throw error if stock profile not found', async () => {
      jest.spyOn(StockProfile, 'init').mockImplementationOnce(() => {
        throw new Error('ProfileId not found');
      });

      jest
        .spyOn(ProductRepository.prototype, 'findOne')
        .mockReturnValueOnce(null as any);

      const product = await ProductJewellery.init({
        productId: data.ProductId,
      });
      try {
        const sessionService = await SessionService.init();
        const loginUser = await LoginUser.init(sessionService);
        loginUser.ObjectId = '1234567890';
        loginUser.ObjectId = '1234567890';
        await product.create(loginUser, {}, data.ProfileId);
      } catch (error) {
        expect(error.message).toEqual(
          'Stock Profile not found. Please create Stock Profile first.',
        );
        expect(error.code).toEqual('ProductJewelleryErrMsg01');
      }
    });
  });
});
