import { EventLog } from '../../../../src/domain/entities/event-log.entity';
import { InstallId } from '../../../../src/domain/value-objects/install-id.vo';
import { EventName } from '../../../../src/domain/value-objects/event-name.vo';
import { EventProperties } from '../../../../src/domain/value-objects/event-properties.vo';

describe('EventLog Entity', () => {
  const createInstallId = () => InstallId.fromString('test-install-id-12345');
  const createEventName = () => EventName.fromString('app_session_start');
  const createEventTime = () => new Date('2025-01-01T12:00:00.000Z');

  describe('create', () => {
    it('should create EventLog with required properties', () => {
      const installId = createInstallId();
      const eventName = createEventName();
      const eventTime = createEventTime();

      const eventLog = EventLog.create({
        installId,
        eventName,
        eventTime,
      });

      expect(eventLog.id).toBeNull();
      expect(eventLog.userId).toBeNull();
      expect(eventLog.installId).toBe(installId);
      expect(eventLog.eventName).toBe(eventName);
      expect(eventLog.eventTime).toEqual(eventTime);
      expect(eventLog.properties).toBeDefined();
      expect(eventLog.createdAt).toBeInstanceOf(Date);
    });

    it('should create EventLog with userId (userSerialNum)', () => {
      const userId = 'D25121400005';  // userSerialNum format
      const eventLog = EventLog.create({
        userId,
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
      });

      expect(eventLog.userId).toBe(userId);
    });

    it('should create EventLog with properties', () => {
      const properties = EventProperties.fromData({
        os: 'iOS',
        osVersion: '17.0',
        appVersion: '1.0.0',
        province: 'Shanghai',
        city: 'Shanghai',
      });

      const eventLog = EventLog.create({
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
        properties,
      });

      expect(eventLog.properties.os).toBe('iOS');
      expect(eventLog.properties.osVersion).toBe('17.0');
      expect(eventLog.properties.province).toBe('Shanghai');
    });

    it('should use empty properties by default', () => {
      const eventLog = EventLog.create({
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
      });

      expect(eventLog.properties.os).toBeUndefined();
      expect(eventLog.properties.data).toEqual({});
    });

    it('should set createdAt to current time', () => {
      const beforeCreate = new Date();
      const eventLog = EventLog.create({
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
      });
      const afterCreate = new Date();

      expect(eventLog.createdAt.getTime()).toBeGreaterThanOrEqual(beforeCreate.getTime());
      expect(eventLog.createdAt.getTime()).toBeLessThanOrEqual(afterCreate.getTime());
    });
  });

  describe('reconstitute', () => {
    it('should reconstitute EventLog from persistence data', () => {
      const id = BigInt(999);
      const userId = 'D25121400123';  // userSerialNum format
      const installId = createInstallId();
      const eventName = createEventName();
      const eventTime = createEventTime();
      const createdAt = new Date('2025-01-01T12:01:00.000Z');
      const properties = EventProperties.fromData({ os: 'Android' });

      const eventLog = EventLog.reconstitute({
        id,
        userId,
        installId,
        eventName,
        eventTime,
        properties,
        createdAt,
      });

      expect(eventLog.id).toBe(id);
      expect(eventLog.userId).toBe(userId);
      expect(eventLog.installId).toBe(installId);
      expect(eventLog.eventName).toBe(eventName);
      expect(eventLog.eventTime).toEqual(eventTime);
      expect(eventLog.properties.os).toBe('Android');
      expect(eventLog.createdAt).toEqual(createdAt);
    });

    it('should handle null userId', () => {
      const eventLog = EventLog.reconstitute({
        id: BigInt(1),
        userId: null,
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
        properties: EventProperties.empty(),
        createdAt: new Date(),
      });

      expect(eventLog.userId).toBeNull();
    });
  });

  describe('dauIdentifier', () => {
    it('should return userId (userSerialNum) when userId exists', () => {
      const userId = 'D25121400005';
      const eventLog = EventLog.create({
        userId,
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
      });

      expect(eventLog.dauIdentifier).toBe('D25121400005');
    });

    it('should return installId value when userId is null', () => {
      const installId = InstallId.fromString('my-install-id-abc');
      const eventLog = EventLog.create({
        installId,
        eventName: createEventName(),
        eventTime: createEventTime(),
      });

      expect(eventLog.dauIdentifier).toBe('my-install-id-abc');
    });

    it('should prefer userId over installId', () => {
      const userId = 'D25121400999';
      const installId = InstallId.fromString('should-not-use-this');
      const eventLog = EventLog.create({
        userId,
        installId,
        eventName: createEventName(),
        eventTime: createEventTime(),
      });

      expect(eventLog.dauIdentifier).toBe('D25121400999');
    });
  });

  describe('getters', () => {
    let eventLog: EventLog;

    beforeEach(() => {
      eventLog = EventLog.reconstitute({
        id: BigInt(100),
        userId: 'D25121400200',
        installId: createInstallId(),
        eventName: createEventName(),
        eventTime: createEventTime(),
        properties: EventProperties.fromData({ appVersion: '2.0.0' }),
        createdAt: new Date('2025-01-01T12:00:00.000Z'),
      });
    });

    it('should return correct id', () => {
      expect(eventLog.id).toBe(BigInt(100));
    });

    it('should return correct userId', () => {
      expect(eventLog.userId).toBe('D25121400200');
    });

    it('should return correct installId', () => {
      expect(eventLog.installId.value).toBe('test-install-id-12345');
    });

    it('should return correct eventName', () => {
      expect(eventLog.eventName.value).toBe('app_session_start');
    });

    it('should return correct eventTime', () => {
      expect(eventLog.eventTime).toEqual(new Date('2025-01-01T12:00:00.000Z'));
    });

    it('should return correct properties', () => {
      expect(eventLog.properties.appVersion).toBe('2.0.0');
    });

    it('should return correct createdAt', () => {
      expect(eventLog.createdAt).toEqual(new Date('2025-01-01T12:00:00.000Z'));
    });
  });
});
