import { UserPreferencesService } from './user-preferences.service';
import { DEFAULT_USER_PREFERENCE } from './user.types';
import type { UpdateUserPreferenceDto } from './user.types';

describe('UserPreferencesService', () => {
  describe('getOrDefault', () => {
    it('returns the stored preference when one exists', async () => {
      const stored = {
        userId: 'u1',
        ...DEFAULT_USER_PREFERENCE,
        preferredPace: 'relaxed',
      };
      const repo = { findByUserId: jest.fn().mockResolvedValue(stored) };
      const service = new UserPreferencesService(repo as never);

      await expect(service.getOrDefault('u1')).resolves.toEqual(stored);
    });

    it('returns an in-memory default without persisting a row when none exists', async () => {
      const repo = {
        findByUserId: jest.fn().mockResolvedValue(undefined),
        upsert: jest.fn(),
      };
      const service = new UserPreferencesService(repo as never);

      const result = await service.getOrDefault('u1');

      expect(result).toEqual({ userId: 'u1', ...DEFAULT_USER_PREFERENCE });
      expect(repo.upsert).not.toHaveBeenCalled();
    });
  });

  describe('upsert', () => {
    it('merges the partial dto onto the current effective preference before persisting', async () => {
      const repo = {
        findByUserId: jest.fn().mockResolvedValue({
          userId: 'u1',
          ...DEFAULT_USER_PREFERENCE,
          preferredPace: 'relaxed',
        }),
        upsert: jest
          .fn()
          .mockImplementation((userId: string, dto: UpdateUserPreferenceDto) =>
            Promise.resolve({ userId, ...DEFAULT_USER_PREFERENCE, ...dto }),
          ),
      };
      const service = new UserPreferencesService(repo as never);

      await service.upsert('u1', { childFriendlyPreferred: true });

      expect(repo.upsert).toHaveBeenCalledWith(
        'u1',
        expect.objectContaining({
          preferredPace: 'relaxed',
          childFriendlyPreferred: true,
        }),
      );
    });
  });
});
