import type { Logger } from '@core/shared/domain/Logger';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import type { UserRepository } from '../../domain/repositories/UserRepository';
import { GetUserUseCase } from './GetUserUseCase';

describe('GetUserUseCase', () => {
  let userRepo: {
    findById: Mock;
  };
  let logger: Logger;
  let useCase: GetUserUseCase;

  beforeEach(() => {
    userRepo = {
      findById: vi.fn(),
    };

    logger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    } as unknown as Logger;

    useCase = new GetUserUseCase(
      userRepo as unknown as UserRepository,
      logger,
    );
  });

  it('returns user when found', async () => {
    const storedUser = {
      id: 'user-1',
      email: 'test@example.com',
      displayName: 'John Smith',
      passwordHash: 'hashed-password',
      createdAt: new Date(),
    };
    userRepo.findById.mockResolvedValue(storedUser);

    const result = await useCase.execute({ userId: 'user-1' });

    expect(result.isOk()).toBe(true);
    const getUserResult = result.unwrap();
    expect(getUserResult.user).toBeDefined();
    expect(getUserResult.user.getId().value).toBe('user-1');
    expect(getUserResult.user.getEmail()).toBe('test@example.com');
    expect(userRepo.findById).toHaveBeenCalledWith('user-1');
  });

  it('returns error when user not found', async () => {
    userRepo.findById.mockResolvedValue(null);

    const result = await useCase.execute({ userId: 'nonexistent' });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr().code).toBe('USER_NOT_FOUND');
  });

  it('returns error on repository failure', async () => {
    userRepo.findById.mockRejectedValue(new Error('Database error'));

    const result = await useCase.execute({ userId: 'user-1' });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
    expect(logger.error).toHaveBeenCalled();
  });
});