/**
 * RateQuote Entity Unit Tests
 */

import { RateQuote } from './rate-quote.entity';

describe('RateQuote Entity', () => {
  const validProps = {
    id: 'quote-1',
    carrierId: 'carrier-1',
    carrierName: 'Maersk',
    carrierCode: 'MAERSK',
    origin: {
      code: 'NLRTM',
      name: 'Rotterdam',
      country: 'Netherlands',
    },
    destination: {
      code: 'USNYC',
      name: 'New York',
      country: 'United States',
    },
    pricing: {
      baseFreight: 1000,
      surcharges: [
        { type: 'BAF', description: 'Bunker Adjustment Factor', amount: 100, currency: 'USD' },
      ],
      totalAmount: 1100,
      currency: 'USD',
    },
    containerType: '40HC',
    mode: 'FCL' as const,
    etd: new Date('2025-11-01'),
    eta: new Date('2025-11-20'),
    transitDays: 19,
    route: [
      {
        portCode: 'NLRTM',
        portName: 'Rotterdam',
        departure: new Date('2025-11-01'),
      },
      {
        portCode: 'USNYC',
        portName: 'New York',
        arrival: new Date('2025-11-20'),
      },
    ],
    availability: 50,
    frequency: 'Weekly',
    vesselType: 'Container Ship',
    co2EmissionsKg: 2500,
  };

  describe('create', () => {
    it('should create rate quote with valid props', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.id).toBe('quote-1');
      expect(rateQuote.carrierName).toBe('Maersk');
      expect(rateQuote.origin.code).toBe('NLRTM');
      expect(rateQuote.destination.code).toBe('USNYC');
      expect(rateQuote.pricing.totalAmount).toBe(1100);
    });

    it('should set validUntil to 15 minutes from now', () => {
      const before = new Date();
      const rateQuote = RateQuote.create(validProps);
      const _after = new Date();

      const expectedValidUntil = new Date(before.getTime() + 15 * 60 * 1000);
      const diff = Math.abs(rateQuote.validUntil.getTime() - expectedValidUntil.getTime());

      // Allow 1 second tolerance for test execution time
      expect(diff).toBeLessThan(1000);
    });

    it('should throw error for non-positive total price', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          pricing: { ...validProps.pricing, totalAmount: 0 },
        })
      ).toThrow('Total price must be positive');
    });

    it('should throw error for non-positive base freight', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          pricing: { ...validProps.pricing, baseFreight: 0 },
        })
      ).toThrow('Base freight must be positive');
    });

    it('should throw error if ETA is not after ETD', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          eta: new Date('2025-10-31'),
        })
      ).toThrow('ETA must be after ETD');
    });

    it('should throw error for non-positive transit days', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          transitDays: 0,
        })
      ).toThrow('Transit days must be positive');
    });

    it('should throw error for negative availability', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          availability: -1,
        })
      ).toThrow('Availability cannot be negative');
    });

    it('should throw error if route has less than 2 segments', () => {
      expect(() =>
        RateQuote.create({
          ...validProps,
          route: [{ portCode: 'NLRTM', portName: 'Rotterdam' }],
        })
      ).toThrow('Route must have at least origin and destination');
    });
  });

  describe('isValid', () => {
    it('should return true for non-expired quote', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.isValid()).toBe(true);
    });

    it('should return false for expired quote', () => {
      const expiredQuote = RateQuote.fromPersistence({
        ...validProps,
        validUntil: new Date(Date.now() - 1000), // 1 second ago
        createdAt: new Date(),
        updatedAt: new Date(),
      });
      expect(expiredQuote.isValid()).toBe(false);
    });
  });

  describe('isExpired', () => {
    it('should return false for non-expired quote', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.isExpired()).toBe(false);
    });

    it('should return true for expired quote', () => {
      const expiredQuote = RateQuote.fromPersistence({
        ...validProps,
        validUntil: new Date(Date.now() - 1000),
        createdAt: new Date(),
        updatedAt: new Date(),
      });
      expect(expiredQuote.isExpired()).toBe(true);
    });
  });

  describe('hasAvailability', () => {
    it('should return true when availability > 0', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.hasAvailability()).toBe(true);
    });

    it('should return false when availability = 0', () => {
      const rateQuote = RateQuote.create({ ...validProps, availability: 0 });
      expect(rateQuote.hasAvailability()).toBe(false);
    });
  });

  describe('getTotalSurcharges', () => {
    it('should calculate total surcharges', () => {
      const rateQuote = RateQuote.create({
        ...validProps,
        pricing: {
          baseFreight: 1000,
          surcharges: [
            { type: 'BAF', description: 'BAF', amount: 100, currency: 'USD' },
            { type: 'CAF', description: 'CAF', amount: 50, currency: 'USD' },
          ],
          totalAmount: 1150,
          currency: 'USD',
        },
      });
      expect(rateQuote.getTotalSurcharges()).toBe(150);
    });
  });

  describe('getTransshipmentCount', () => {
    it('should return 0 for direct route', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.getTransshipmentCount()).toBe(0);
    });

    it('should return correct count for route with transshipments', () => {
      const rateQuote = RateQuote.create({
        ...validProps,
        route: [
          { portCode: 'NLRTM', portName: 'Rotterdam' },
          { portCode: 'ESBCN', portName: 'Barcelona' },
          { portCode: 'USNYC', portName: 'New York' },
        ],
      });
      expect(rateQuote.getTransshipmentCount()).toBe(1);
    });
  });

  describe('isDirectRoute', () => {
    it('should return true for direct route', () => {
      const rateQuote = RateQuote.create(validProps);
      expect(rateQuote.isDirectRoute()).toBe(true);
    });

    it('should return false for route with transshipments', () => {
      const rateQuote = RateQuote.create({
        ...validProps,
        route: [
          { portCode: 'NLRTM', portName: 'Rotterdam' },
          { portCode: 'ESBCN', portName: 'Barcelona' },
          { portCode: 'USNYC', portName: 'New York' },
        ],
      });
      expect(rateQuote.isDirectRoute()).toBe(false);
    });
  });

  describe('getPricePerDay', () => {
    it('should calculate price per day', () => {
      const rateQuote = RateQuote.create(validProps);
      const pricePerDay = rateQuote.getPricePerDay();
      expect(pricePerDay).toBeCloseTo(1100 / 19, 2);
    });
  });
});
