/**
 * License Entity Tests
 *
 * Unit tests for the License domain entity
 */

import { License } from './license.entity';

describe('License Entity', () => {
  const createValidLicense = () => {
    return License.create({
      id: 'license-123',
      subscriptionId: 'sub-123',
      userId: 'user-123',
    });
  };

  describe('create', () => {
    it('should create a license with valid data', () => {
      const license = createValidLicense();

      expect(license.id).toBe('license-123');
      expect(license.subscriptionId).toBe('sub-123');
      expect(license.userId).toBe('user-123');
      expect(license.status.value).toBe('ACTIVE');
      expect(license.assignedAt).toBeInstanceOf(Date);
      expect(license.revokedAt).toBeNull();
    });

    it('should create a license with different user', () => {
      const license = License.create({
        id: 'license-456',
        subscriptionId: 'sub-123',
        userId: 'user-456',
      });

      expect(license.userId).toBe('user-456');
    });
  });

  describe('fromPersistence', () => {
    it('should reconstitute an active license from persistence data', () => {
      const assignedAt = new Date('2024-01-15');
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'ACTIVE',
        assignedAt,
        revokedAt: null,
      });

      expect(license.id).toBe('license-123');
      expect(license.status.value).toBe('ACTIVE');
      expect(license.assignedAt).toEqual(assignedAt);
      expect(license.revokedAt).toBeNull();
    });

    it('should reconstitute a revoked license from persistence data', () => {
      const revokedAt = new Date('2024-02-01');
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt,
      });

      expect(license.status.value).toBe('REVOKED');
      expect(license.revokedAt).toEqual(revokedAt);
    });
  });

  describe('isActive', () => {
    it('should return true for active license', () => {
      const license = createValidLicense();
      expect(license.isActive()).toBe(true);
    });

    it('should return false for revoked license', () => {
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt: new Date('2024-02-01'),
      });

      expect(license.isActive()).toBe(false);
    });
  });

  describe('isRevoked', () => {
    it('should return false for active license', () => {
      const license = createValidLicense();
      expect(license.isRevoked()).toBe(false);
    });

    it('should return true for revoked license', () => {
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt: new Date('2024-02-01'),
      });

      expect(license.isRevoked()).toBe(true);
    });
  });

  describe('revoke', () => {
    it('should revoke an active license', () => {
      const license = createValidLicense();
      const revoked = license.revoke();

      expect(revoked.status.value).toBe('REVOKED');
      expect(revoked.revokedAt).toBeInstanceOf(Date);
      expect(revoked.isActive()).toBe(false);
    });

    it('should throw when revoking an already revoked license', () => {
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt: new Date('2024-02-01'),
      });

      expect(() => license.revoke()).toThrow('License is already revoked');
    });

    it('should preserve original data when revoking', () => {
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-456',
        userId: 'user-789',
        status: 'ACTIVE',
        assignedAt: new Date('2024-01-15'),
        revokedAt: null,
      });

      const revoked = license.revoke();

      expect(revoked.id).toBe('license-123');
      expect(revoked.subscriptionId).toBe('sub-456');
      expect(revoked.userId).toBe('user-789');
      expect(revoked.assignedAt).toEqual(new Date('2024-01-15'));
    });
  });

  describe('reactivate', () => {
    it('should reactivate a revoked license', () => {
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt: new Date('2024-02-01'),
      });

      const reactivated = license.reactivate();

      expect(reactivated.status.value).toBe('ACTIVE');
      expect(reactivated.revokedAt).toBeNull();
    });

    it('should throw when reactivating an active license', () => {
      const license = createValidLicense();

      expect(() => license.reactivate()).toThrow('License is already active');
    });
  });

  describe('getActiveDuration', () => {
    it('should calculate duration for active license', () => {
      const assignedAt = new Date();
      assignedAt.setHours(assignedAt.getHours() - 1); // 1 hour ago

      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'ACTIVE',
        assignedAt,
        revokedAt: null,
      });

      const duration = license.getActiveDuration();
      // Should be approximately 1 hour in milliseconds (allow some variance)
      expect(duration).toBeGreaterThan(3600000 - 1000);
      expect(duration).toBeLessThan(3600000 + 1000);
    });

    it('should calculate duration for revoked license', () => {
      const assignedAt = new Date('2024-01-15T10:00:00Z');
      const revokedAt = new Date('2024-01-15T12:00:00Z'); // 2 hours later

      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt,
        revokedAt,
      });

      const duration = license.getActiveDuration();
      expect(duration).toBe(2 * 60 * 60 * 1000); // 2 hours in ms
    });
  });

  describe('toObject', () => {
    it('should convert to plain object for persistence', () => {
      const license = createValidLicense();
      const obj = license.toObject();

      expect(obj.id).toBe('license-123');
      expect(obj.subscriptionId).toBe('sub-123');
      expect(obj.userId).toBe('user-123');
      expect(obj.status).toBe('ACTIVE');
      expect(obj.assignedAt).toBeInstanceOf(Date);
      expect(obj.revokedAt).toBeNull();
    });

    it('should include revokedAt for revoked license', () => {
      const revokedAt = new Date('2024-02-01');
      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-123',
        userId: 'user-123',
        status: 'REVOKED',
        assignedAt: new Date('2024-01-15'),
        revokedAt,
      });

      const obj = license.toObject();
      expect(obj.status).toBe('REVOKED');
      expect(obj.revokedAt).toEqual(revokedAt);
    });
  });

  describe('property accessors', () => {
    it('should correctly expose all properties', () => {
      const assignedAt = new Date('2024-01-15');

      const license = License.fromPersistence({
        id: 'license-123',
        subscriptionId: 'sub-456',
        userId: 'user-789',
        status: 'ACTIVE',
        assignedAt,
        revokedAt: null,
      });

      expect(license.id).toBe('license-123');
      expect(license.subscriptionId).toBe('sub-456');
      expect(license.userId).toBe('user-789');
      expect(license.status.value).toBe('ACTIVE');
      expect(license.assignedAt).toEqual(assignedAt);
      expect(license.revokedAt).toBeNull();
    });
  });
});
