import { describe, it, expect } from 'vitest';
import {
  isDownloadAvailable,
  selectPreferredAvailability,
  calculateEstimatedDate,
  hasValidPrice,
  isPriceMaintained,
} from './availability.helpers';
import { AvailabilityDTO } from '@generated/swagger/availability-api';

describe('Availability Helpers', () => {
  const mockAvailability: AvailabilityDTO = {
    itemId: 123,
    status: 1024,
    preferred: 1,
    qty: 5,
    supplierId: 1,
    at: '2025-10-15',
    altAt: '2025-10-20',
    requestStatusCode: '0',
    price: {
      value: { value: 19.99, currency: 'EUR', currencySymbol: '€' },
      vat: { value: 3.8, inPercent: 19, label: '19%', vatType: 1 },
    },
    priceMaintained: true,
  };

  describe('isDownloadAvailable', () => {
    it('should return false for null availability', () => {
      expect(isDownloadAvailable(null)).toBe(false);
    });

    it('should return false for undefined availability', () => {
      expect(isDownloadAvailable(undefined)).toBe(false);
    });

    it('should return false for supplier 16 with 0 stock', () => {
      const unavailable: AvailabilityDTO = {
        ...mockAvailability,
        supplierId: 16,
        qty: 0,
        status: 1024,
      };

      expect(isDownloadAvailable(unavailable)).toBe(false);
    });

    it('should return true for supplier 16 with stock > 0', () => {
      const available: AvailabilityDTO = {
        ...mockAvailability,
        supplierId: 16,
        qty: 5,
        status: 1024,
      };

      expect(isDownloadAvailable(available)).toBe(true);
    });

    it('should return true for valid availability codes', () => {
      const validCodes = [2, 32, 256, 1024, 2048, 4096];

      for (const code of validCodes) {
        const availability: AvailabilityDTO = {
          ...mockAvailability,
          status: code,
          supplierId: 1,
        };

        expect(isDownloadAvailable(availability)).toBe(true);
      }
    });

    it('should return false for invalid availability codes', () => {
      const invalidCodes = [0, 1, 512, 8192, 16384, 999];

      for (const code of invalidCodes) {
        const availability: AvailabilityDTO = {
          ...mockAvailability,
          status: code,
          supplierId: 1,
        };

        expect(isDownloadAvailable(availability)).toBe(false);
      }
    });
  });

  describe('selectPreferredAvailability', () => {
    it('should return undefined for empty array', () => {
      expect(selectPreferredAvailability([])).toBeUndefined();
    });

    it('should select availability with preferred === 1', () => {
      const availabilities: AvailabilityDTO[] = [
        { ...mockAvailability, preferred: 0 },
        { ...mockAvailability, preferred: 1 },
        { ...mockAvailability, preferred: 0 },
      ];

      const result = selectPreferredAvailability(availabilities);
      expect(result?.preferred).toBe(1);
    });

    it('should return first preferred when multiple have preferred === 1', () => {
      const availabilities: AvailabilityDTO[] = [
        { ...mockAvailability, preferred: 0, itemId: 1 },
        { ...mockAvailability, preferred: 1, itemId: 2 },
        { ...mockAvailability, preferred: 1, itemId: 3 },
      ];

      const result = selectPreferredAvailability(availabilities);
      expect(result?.itemId).toBe(2);
    });

    it('should return undefined when no preferred availability', () => {
      const availabilities: AvailabilityDTO[] = [
        { ...mockAvailability, preferred: 0 },
        { ...mockAvailability, preferred: 0 },
      ];

      expect(selectPreferredAvailability(availabilities)).toBeUndefined();
    });
  });

  describe('calculateEstimatedDate', () => {
    it('should return undefined for null availability', () => {
      expect(calculateEstimatedDate(null)).toBeUndefined();
    });

    it('should return undefined for undefined availability', () => {
      expect(calculateEstimatedDate(undefined)).toBeUndefined();
    });

    it('should return altAt when requestStatusCode is 32', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        requestStatusCode: '32',
        at: '2025-10-15',
        altAt: '2025-10-20',
      };

      expect(calculateEstimatedDate(availability)).toBe('2025-10-20');
    });

    it('should return at when requestStatusCode is not 32', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        requestStatusCode: '0',
        at: '2025-10-15',
        altAt: '2025-10-20',
      };

      expect(calculateEstimatedDate(availability)).toBe('2025-10-15');
    });

    it('should return at when requestStatusCode is undefined', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        at: '2025-10-15',
        altAt: '2025-10-20',
      };

      expect(calculateEstimatedDate(availability)).toBe('2025-10-15');
    });

    it('should handle missing dates', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        at: undefined,
        altAt: undefined,
      };

      expect(calculateEstimatedDate(availability)).toBeUndefined();
    });
  });

  describe('hasValidPrice', () => {
    it('should return false for null availability', () => {
      expect(hasValidPrice(null)).toBe(false);
    });

    it('should return false for undefined availability', () => {
      expect(hasValidPrice(undefined)).toBe(false);
    });

    it('should return true for availability with valid price', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        price: {
          value: { value: 19.99, currency: 'EUR', currencySymbol: '€' },
        },
      };

      expect(hasValidPrice(availability)).toBe(true);
    });

    it('should return false for availability without price', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        price: undefined,
      };

      expect(hasValidPrice(availability)).toBe(false);
    });

    it('should return false for availability with price value 0', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        price: {
          value: { value: 0, currency: 'EUR' },
        },
      };

      expect(hasValidPrice(availability)).toBe(false);
    });

    it('should return false for availability with negative price', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        price: {
          value: { value: -10, currency: 'EUR' },
        },
      };

      expect(hasValidPrice(availability)).toBe(false);
    });

    it('should return false for availability with missing value object', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        price: {} as any,
      };

      expect(hasValidPrice(availability)).toBe(false);
    });
  });

  describe('isPriceMaintained', () => {
    it('should return false for null availability', () => {
      expect(isPriceMaintained(null)).toBe(false);
    });

    it('should return false for undefined availability', () => {
      expect(isPriceMaintained(undefined)).toBe(false);
    });

    it('should return true when priceMaintained is true', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        priceMaintained: true,
      };

      expect(isPriceMaintained(availability)).toBe(true);
    });

    it('should return false when priceMaintained is false', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        priceMaintained: false,
      };

      expect(isPriceMaintained(availability)).toBe(false);
    });

    it('should return false when priceMaintained is undefined', () => {
      const availability: AvailabilityDTO = {
        ...mockAvailability,
        priceMaintained: undefined,
      };

      expect(isPriceMaintained(availability)).toBe(false);
    });
  });
});
