import { describe, it, expect, vi, beforeEach } from 'vitest';
import { UsersService } from '../../../src/modules/users/users.service.js';
import { NotFoundError } from '../../../src/common/errors.js';

describe('UsersService', () => {
  const mockRepo = {
    findByKeycloakId: vi.fn(),
    findById: vi.fn(),
    create: vi.fn(),
    update: vi.fn(),
    upsertFromToken: vi.fn(),
  };

  let service: UsersService;

  beforeEach(() => {
    vi.clearAllMocks();
    service = new UsersService({ usersRepository: mockRepo as never });
  });

  describe('syncFromToken', () => {
    it('upserts user from auth token data', async () => {
      const authUser = {
        keycloakId: 'kc-1',
        email: 'test@example.com',
        displayName: 'Test User',
        roles: ['member'],
        householdIds: [],
      };
      const upserted = { _id: 'u1', ...authUser };
      mockRepo.upsertFromToken.mockResolvedValue(upserted);

      const result = await service.syncFromToken(authUser);

      expect(mockRepo.upsertFromToken).toHaveBeenCalledWith(
        'kc-1',
        'test@example.com',
        'Test User',
      );
      expect(result).toEqual(upserted);
    });
  });

  describe('getProfile', () => {
    it('returns user when found', async () => {
      const user = { _id: 'u1', keycloakId: 'kc-1', displayName: 'Test' };
      mockRepo.findByKeycloakId.mockResolvedValue(user);

      const result = await service.getProfile('kc-1');

      expect(result).toEqual(user);
      expect(mockRepo.findByKeycloakId).toHaveBeenCalledWith('kc-1');
    });

    it('throws NotFoundError when user not found', async () => {
      mockRepo.findByKeycloakId.mockResolvedValue(null);

      await expect(service.getProfile('kc-missing')).rejects.toThrow(NotFoundError);
    });
  });
});
