import { describe, it, expect } from 'vitest';
import { SessionLifetime } from 'apps/companion/main/automation/domain/value-objects/SessionLifetime';

describe('SessionLifetime Value Object', () => {
  describe('Construction', () => {
    it('should create with valid expiry date', () => {
      const futureDate = new Date(Date.now() + 3600000);
      expect(() => new SessionLifetime(futureDate)).not.toThrow();
    });

    it('should create with null expiry (no expiration)', () => {
      expect(() => new SessionLifetime(null)).not.toThrow();
    });

    it('should reject invalid dates', () => {
      const invalidDate = new Date('invalid');
      expect(() => new SessionLifetime(invalidDate)).toThrow();
    });

    it('should reject dates in the past', () => {
      const pastDate = new Date(Date.now() - 3600000);
      expect(() => new SessionLifetime(pastDate)).toThrow();
    });
  });

  describe('isExpired()', () => {
    it('should return true for expired date', () => {
      const pastDate = new Date(Date.now() - 1000);
      const lifetime = new SessionLifetime(pastDate);
      expect(lifetime.isExpired()).toBe(true);
    });

    it('should return false for valid future date', () => {
      const futureDate = new Date(Date.now() + 3600000);
      const lifetime = new SessionLifetime(futureDate);
      expect(lifetime.isExpired()).toBe(false);
    });

    it('should return false for null expiry (never expires)', () => {
      const lifetime = new SessionLifetime(null);
      expect(lifetime.isExpired()).toBe(false);
    });

    it('should consider buffer time (5 minutes)', () => {
      const nearExpiryDate = new Date(Date.now() + 240000);
      const lifetime = new SessionLifetime(nearExpiryDate);
      expect(lifetime.isExpired()).toBe(true);
    });

    it('should not consider expired when beyond buffer', () => {
      const safeDate = new Date(Date.now() + 360000);
      const lifetime = new SessionLifetime(safeDate);
      expect(lifetime.isExpired()).toBe(false);
    });
  });

  describe('isExpiringSoon()', () => {
    it('should return true for date within buffer window', () => {
      const soonDate = new Date(Date.now() + 240000);
      const lifetime = new SessionLifetime(soonDate);
      expect(lifetime.isExpiringSoon()).toBe(true);
    });

    it('should return false for date far in future', () => {
      const farDate = new Date(Date.now() + 3600000);
      const lifetime = new SessionLifetime(farDate);
      expect(lifetime.isExpiringSoon()).toBe(false);
    });

    it('should return false for null expiry', () => {
      const lifetime = new SessionLifetime(null);
      expect(lifetime.isExpiringSoon()).toBe(false);
    });

    it('should return true exactly at buffer boundary (5 minutes)', () => {
      const boundaryDate = new Date(Date.now() + 300000);
      const lifetime = new SessionLifetime(boundaryDate);
      expect(lifetime.isExpiringSoon()).toBe(true);
    });
  });

  describe('Edge Cases', () => {
    it('should handle timezone correctly', () => {
      const utcDate = new Date('2025-12-31T23:59:59Z');
      const lifetime = new SessionLifetime(utcDate);
      expect(lifetime.getExpiry()).toEqual(utcDate);
    });

    it('should handle millisecond precision', () => {
      const preciseDate = new Date(Date.now() + 299999);
      const lifetime = new SessionLifetime(preciseDate);
      expect(lifetime.isExpiringSoon()).toBe(true);
    });

    it('should provide remaining time', () => {
      const futureDate = new Date(Date.now() + 3600000);
      const lifetime = new SessionLifetime(futureDate);
      const remaining = lifetime.getRemainingTime();
      expect(remaining).toBeGreaterThan(3000000);
      expect(remaining).toBeLessThanOrEqual(3600000);
    });
  });
});