import { EventName } from '../../../../src/domain/value-objects/event-name.vo';
import { DomainException } from '../../../../src/shared/exceptions/domain.exception';

describe('EventName Value Object', () => {
  describe('fromString', () => {
    it('should create EventName from valid string', () => {
      const eventName = EventName.fromString('app_session_start');
      expect(eventName.value).toBe('app_session_start');
    });

    it('should convert to lowercase', () => {
      const eventName = EventName.fromString('APP_SESSION_START');
      expect(eventName.value).toBe('app_session_start');
    });

    it('should trim whitespace', () => {
      const eventName = EventName.fromString('  app_session_start  ');
      expect(eventName.value).toBe('app_session_start');
    });

    it('should accept event names with numbers', () => {
      const eventName = EventName.fromString('event_v2_click');
      expect(eventName.value).toBe('event_v2_click');
    });

    it('should throw DomainException for empty string', () => {
      expect(() => EventName.fromString('')).toThrow(DomainException);
      expect(() => EventName.fromString('')).toThrow('EventName cannot be empty');
    });

    it('should throw DomainException for whitespace only string', () => {
      expect(() => EventName.fromString('   ')).toThrow(DomainException);
    });

    it('should throw DomainException for string starting with number', () => {
      expect(() => EventName.fromString('123_event')).toThrow(DomainException);
      expect(() => EventName.fromString('123_event')).toThrow(
        'EventName must start with letter and contain only lowercase letters, numbers, and underscores',
      );
    });

    it('should throw DomainException for string starting with underscore', () => {
      expect(() => EventName.fromString('_event')).toThrow(DomainException);
    });

    it('should throw DomainException for string with invalid characters', () => {
      expect(() => EventName.fromString('app-session')).toThrow(DomainException);
      expect(() => EventName.fromString('app.session')).toThrow(DomainException);
      expect(() => EventName.fromString('app session')).toThrow(DomainException);
    });

    it('should throw DomainException for too long string', () => {
      const longString = 'a'.repeat(65);
      expect(() => EventName.fromString(longString)).toThrow(DomainException);
      expect(() => EventName.fromString(longString)).toThrow('EventName cannot exceed 64 characters');
    });

    it('should accept exactly 64 characters', () => {
      const maxString = 'a'.repeat(64);
      const eventName = EventName.fromString(maxString);
      expect(eventName.value.length).toBe(64);
    });
  });

  describe('predefined events', () => {
    it('should have APP_SESSION_START predefined', () => {
      expect(EventName.APP_SESSION_START.value).toBe('app_session_start');
    });

    it('should have PRESENCE_HEARTBEAT predefined', () => {
      expect(EventName.PRESENCE_HEARTBEAT.value).toBe('presence_heartbeat');
    });

    it('should have APP_SESSION_END predefined', () => {
      expect(EventName.APP_SESSION_END.value).toBe('app_session_end');
    });
  });

  describe('isDauEvent', () => {
    it('should return true for app_session_start', () => {
      const eventName = EventName.fromString('app_session_start');
      expect(eventName.isDauEvent()).toBe(true);
    });

    it('should return true for predefined APP_SESSION_START', () => {
      expect(EventName.APP_SESSION_START.isDauEvent()).toBe(true);
    });

    it('should return false for other events', () => {
      const eventName = EventName.fromString('presence_heartbeat');
      expect(eventName.isDauEvent()).toBe(false);
    });

    it('should return false for PRESENCE_HEARTBEAT', () => {
      expect(EventName.PRESENCE_HEARTBEAT.isDauEvent()).toBe(false);
    });
  });

  describe('equals', () => {
    it('should return true for same values', () => {
      const name1 = EventName.fromString('app_session_start');
      const name2 = EventName.fromString('app_session_start');
      expect(name1.equals(name2)).toBe(true);
    });

    it('should return true for same values with different cases', () => {
      const name1 = EventName.fromString('app_session_start');
      const name2 = EventName.fromString('APP_SESSION_START');
      expect(name1.equals(name2)).toBe(true);
    });

    it('should return false for different values', () => {
      const name1 = EventName.fromString('app_session_start');
      const name2 = EventName.fromString('app_session_end');
      expect(name1.equals(name2)).toBe(false);
    });
  });

  describe('toString', () => {
    it('should return the string value', () => {
      const eventName = EventName.fromString('app_session_start');
      expect(eventName.toString()).toBe('app_session_start');
    });
  });
});
