import { describe, it, expect } from 'vitest';
import { ItemType, ItemTypeSchema } from './item-type.schema';

describe('ItemTypeSchema', () => {
  describe('Individual flags', () => {
    it('should accept NotSet (0)', () => {
      const result = ItemTypeSchema.parse(ItemType.NotSet);
      expect(result).toBe(0);
    });

    it('should accept SingleUnit', () => {
      const result = ItemTypeSchema.parse(ItemType.SingleUnit);
      expect(result).toBe(1);
    });

    it('should accept Download', () => {
      const result = ItemTypeSchema.parse(ItemType.Download);
      expect(result).toBe(4096);
    });

    it('should accept ItemPrice', () => {
      const result = ItemTypeSchema.parse(ItemType.ItemPrice);
      expect(result).toBe(16384);
    });

    it('should accept all defined item type values', () => {
      const allTypes = Object.values(ItemType);

      for (const type of allTypes) {
        expect(() => ItemTypeSchema.parse(type)).not.toThrow();
      }
    });
  });

  describe('Bitwise combined flags', () => {
    it('should accept Download | ItemPrice (20480)', () => {
      const combined = ItemType.Download | ItemType.ItemPrice; // 4096 | 16384 = 20480
      const result = ItemTypeSchema.parse(combined);
      expect(result).toBe(20480);
    });

    it('should accept SingleUnit | Download', () => {
      const combined = ItemType.SingleUnit | ItemType.Download; // 1 | 4096 = 4097
      const result = ItemTypeSchema.parse(combined);
      expect(result).toBe(4097);
    });

    it('should accept Set | Configurable | Discount', () => {
      const combined = ItemType.Set | ItemType.Configurable | ItemType.Discount; // 4 | 16 | 32 = 52
      const result = ItemTypeSchema.parse(combined);
      expect(result).toBe(52);
    });

    it('should accept multiple combined flags', () => {
      const combined =
        ItemType.SingleUnit |
        ItemType.SalesUnit |
        ItemType.Download |
        ItemType.Streaming; // 1 | 2 | 4096 | 8192 = 12291
      const result = ItemTypeSchema.parse(combined);
      expect(result).toBe(12291);
    });

    it('should accept all flags combined', () => {
      const allFlags = Object.values(ItemType).reduce<number>((a, b) => a | b, 0);
      const result = ItemTypeSchema.parse(allFlags);
      expect(result).toBe(allFlags);
    });
  });

  describe('Invalid values', () => {
    it('should reject unknown flag bit (131072)', () => {
      const unknownFlag = 131072; // Not a valid ItemType flag
      expect(() => ItemTypeSchema.parse(unknownFlag)).toThrow('Invalid ItemType: contains unknown flags');
    });

    it('should reject value with unknown bits', () => {
      const invalidValue = ItemType.Download | 262144; // Valid flag + unknown bit
      expect(() => ItemTypeSchema.parse(invalidValue)).toThrow('Invalid ItemType: contains unknown flags');
    });

    it('should reject negative values', () => {
      expect(() => ItemTypeSchema.parse(-1)).toThrow();
    });

    it('should reject non-integer values', () => {
      expect(() => ItemTypeSchema.parse(1.5)).toThrow();
    });

    it('should reject string values', () => {
      expect(() => ItemTypeSchema.parse('Download' as any)).toThrow();
    });

    it('should reject null', () => {
      expect(() => ItemTypeSchema.parse(null as any)).toThrow();
    });

    it('should reject undefined', () => {
      expect(() => ItemTypeSchema.parse(undefined as any)).toThrow();
    });
  });

  describe('Edge cases', () => {
    it('should handle 0 (NotSet)', () => {
      const result = ItemTypeSchema.parse(0);
      expect(result).toBe(0);
    });

    it('should handle maximum valid combined value', () => {
      // All flags OR'd together
      const maxValue = Object.values(ItemType).reduce<number>((a, b) => a | b, 0);
      const result = ItemTypeSchema.parse(maxValue);
      expect(result).toBe(maxValue);
    });

    it('should handle SingleUnitItemPrice (16385)', () => {
      // This is a special case: not a power of 2, but still valid
      const result = ItemTypeSchema.parse(ItemType.SingleUnitItemPrice);
      expect(result).toBe(16385);
    });

    it('should allow SingleUnitItemPrice in combinations', () => {
      const combined = ItemType.SingleUnitItemPrice | ItemType.Download; // 16385 | 4096 = 20481
      const result = ItemTypeSchema.parse(combined);
      expect(result).toBe(20481);
    });
  });

  describe('Real-world scenarios', () => {
    it('should validate download audiobook item type from bug #5429', () => {
      // This is the actual value that caused the bug
      const downloadAudiobookType = 20480; // ItemPrice | Download
      expect(() => ItemTypeSchema.parse(downloadAudiobookType)).not.toThrow();
      const result = ItemTypeSchema.parse(downloadAudiobookType);
      expect(result).toBe(20480);
    });

    it('should validate e-book item type', () => {
      const ebookType = ItemType.Download | ItemType.SingleUnit;
      expect(() => ItemTypeSchema.parse(ebookType)).not.toThrow();
    });

    it('should validate physical book with various flags', () => {
      const physicalBook = ItemType.SingleUnit | ItemType.SalesUnit;
      expect(() => ItemTypeSchema.parse(physicalBook)).not.toThrow();
    });
  });
});
