/**
 * Unit tests for UserRatingRepository
 */

import { UserRating } from '../value-objects/UserRating';
import { UserRatingRepository } from './UserRatingRepository';

// In-memory test implementation
class InMemoryUserRatingRepository implements UserRatingRepository {
  private ratings: Map<string, UserRating> = new Map();

  async findByUserId(userId: string): Promise<UserRating | null> {
    return this.ratings.get(userId) || null;
  }

  async save(userRating: UserRating): Promise<UserRating> {
    this.ratings.set(userRating.userId, userRating);
    return userRating;
  }
}

describe('UserRatingRepository', () => {
  let repository: InMemoryUserRatingRepository;

  beforeEach(() => {
    repository = new InMemoryUserRatingRepository();
  });

  describe('save', () => {
    it('should save a new user rating', async () => {
      const rating = UserRating.create('user-1');
      const saved = await repository.save(rating);

      expect(saved).toEqual(rating);

      const found = await repository.findByUserId('user-1');
      expect(found).toEqual(rating);
    });

    it('should update existing user rating', async () => {
      const rating1 = UserRating.create('user-1');
      await repository.save(rating1);

      // Update the saved rating (not create a new one)
      const updated = rating1.updateDriverRating(75);
      await repository.save(updated);

      const found = await repository.findByUserId('user-1');
      expect(found).toEqual(updated);
      // Value will be ~57.5 due to EMA from base 50
      expect(found!.driver.value).toBeGreaterThan(50);
      expect(found!.driver.value).toBeLessThan(75);
    });
  });

  describe('findByUserId', () => {
    it('should return rating for existing user', async () => {
      const rating = UserRating.create('user-1');
      await repository.save(rating);

      const found = await repository.findByUserId('user-1');
      expect(found).toEqual(rating);
      expect(found!.userId).toBe('user-1');
    });

    it('should return null for non-existent user', async () => {
      const found = await repository.findByUserId('non-existent');
      expect(found).toBeNull();
    });

    it('should handle multiple users independently', async () => {
      const rating1 = UserRating.create('user-1');
      const rating2 = UserRating.create('user-2');

      const updated1 = rating1.updateDriverRating(60);
      const updated2 = rating2.updateDriverRating(80);

      await repository.save(updated1);
      await repository.save(updated2);

      const found1 = await repository.findByUserId('user-1');
      const found2 = await repository.findByUserId('user-2');

      // Both should have different values (EMA from base 50)
      expect(found1!.driver.value).not.toBe(found2!.driver.value);
      expect(found1!.userId).toBe('user-1');
      expect(found2!.userId).toBe('user-2');
    });
  });
});