import { ExternalGameRatingProfile } from '@core/identity/domain/entities/ExternalGameRatingProfile';
import { ExternalRating } from '@core/identity/domain/value-objects/ExternalRating';
import { ExternalRatingProvenance } from '@core/identity/domain/value-objects/ExternalRatingProvenance';
import { GameKey } from '@core/identity/domain/value-objects/GameKey';
import { UserId } from '@core/identity/domain/value-objects/UserId';
import { ExternalGameRatingProfileOrmEntity } from '../entities/ExternalGameRatingProfileOrmEntity';
import { ExternalGameRatingProfileOrmMapper } from './ExternalGameRatingProfileOrmMapper';

describe('ExternalGameRatingProfileOrmMapper', () => {
  describe('toDomain', () => {
    it('should convert ORM entity to domain entity', () => {
      const now = new Date('2024-01-01');
      const entity = new ExternalGameRatingProfileOrmEntity();
      entity.userId = 'user-123';
      entity.gameKey = 'iracing';
      entity.ratings = [
        { type: 'safety', gameKey: 'iracing', value: 85.5 },
        { type: 'skill', gameKey: 'iracing', value: 92.0 },
      ];
      entity.provenance = {
        source: 'iracing',
        lastSyncedAt: now,
        verified: true,
      };
      entity.createdAt = now;
      entity.updatedAt = now;

      const domain = ExternalGameRatingProfileOrmMapper.toDomain(entity);

      expect(domain.userId.toString()).toBe('user-123');
      expect(domain.gameKey.toString()).toBe('iracing');
      expect(domain.ratings.size).toBe(2);
      expect(domain.provenance.source).toBe('iracing');
      expect(domain.provenance.verified).toBe(true);
    });
  });

  describe('toOrmEntity', () => {
    it('should convert domain entity to ORM entity', () => {
      const domain = createTestDomainEntity('user-123', 'iracing');
      
      const entity = ExternalGameRatingProfileOrmMapper.toOrmEntity(domain);

      expect(entity.userId).toBe('user-123');
      expect(entity.gameKey).toBe('iracing');
      expect(entity.ratings).toHaveLength(2);
      expect(entity.provenance.source).toBe('iracing');
      expect(entity.provenance.verified).toBe(false);
      expect(entity.createdAt).toBeInstanceOf(Date);
      expect(entity.updatedAt).toBeInstanceOf(Date);
    });
  });

  describe('updateOrmEntity', () => {
    it('should update existing ORM entity from domain', () => {
      const existingEntity = new ExternalGameRatingProfileOrmEntity();
      existingEntity.userId = 'user-123';
      existingEntity.gameKey = 'iracing';
      existingEntity.ratings = [
        { type: 'safety', gameKey: 'iracing', value: 85.5 },
      ];
      existingEntity.provenance = {
        source: 'iracing',
        lastSyncedAt: new Date('2024-01-01'),
        verified: false,
      };
      existingEntity.createdAt = new Date('2024-01-01');
      existingEntity.updatedAt = new Date('2024-01-01');

      const domain = createTestDomainEntity('user-123', 'iracing');
      // Update domain with new data
      domain.updateLastSyncedAt(new Date('2024-01-02'));
      domain.markVerified();

      const updated = ExternalGameRatingProfileOrmMapper.updateOrmEntity(existingEntity, domain);

      expect(updated.ratings).toHaveLength(2);
      expect(updated.provenance.verified).toBe(true);
      expect(updated.provenance.lastSyncedAt).toEqual(new Date('2024-01-02'));
      // updatedAt should be updated (may be same timestamp if test runs fast)
      expect(updated.updatedAt.getTime()).toBeGreaterThanOrEqual(existingEntity.updatedAt.getTime());
      // createdAt should be preserved from existing entity
      expect(updated.createdAt).toEqual(existingEntity.createdAt);
    });
  });

  function createTestDomainEntity(userId: string, gameKey: string): ExternalGameRatingProfile {
    const user = UserId.fromString(userId);
    const game = GameKey.create(gameKey);
    const ratings = new Map([
      ['safety', ExternalRating.create(game, 'safety', 85.5)],
      ['skill', ExternalRating.create(game, 'skill', 92.0)],
    ]);
    const provenance = ExternalRatingProvenance.create({
      source: gameKey,
      lastSyncedAt: new Date('2024-01-01'),
      verified: false,
    });

    return ExternalGameRatingProfile.create({
      userId: user,
      gameKey: game,
      ratings,
      provenance,
    });
  }
});