import { Driver } from '@core/racing/domain/entities/Driver';
import type { Logger } from '@core/shared/domain/Logger';
import { beforeEach, describe, expect, it, vi, type Mock } from 'vitest';
import { SocialGraphRepository } from '../../domain/repositories/SocialGraphRepository';
import {
    GetCurrentUserSocialUseCase,
    type GetCurrentUserSocialApplicationError,
    type GetCurrentUserSocialInput,
} from './GetCurrentUserSocialUseCase';

describe('GetCurrentUserSocialUseCase', () => {
  let socialGraphRepository: {
    getFriends: Mock;
    getFriendIds: Mock;
    getSuggestedFriends: Mock;
  };
  let logger: {
    debug: Mock;
    info: Mock;
    warn: Mock;
    error: Mock;
  };
  let useCase: GetCurrentUserSocialUseCase;

  beforeEach(() => {
    socialGraphRepository = {
      getFriends: vi.fn(),
      getFriendIds: vi.fn(),
      getSuggestedFriends: vi.fn(),
    };

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

    useCase = new GetCurrentUserSocialUseCase(
      socialGraphRepository as unknown as SocialGraphRepository, 
      logger as unknown as Logger
    );
  });

  it('returns current user social with mapped friends', async () => {
    vi.useFakeTimers();
    vi.setSystemTime(new Date('2025-01-01T00:00:00.000Z'));

    const friends = [
      Driver.create({
        id: 'friend-1',
        iracingId: '123',
        name: 'Friend One',
        country: 'US',
      }),
    ];

    socialGraphRepository.getFriends.mockResolvedValue(friends);

    const input: GetCurrentUserSocialInput = { driverId: 'driver-1' };
    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const socialResult = result.unwrap();

    expect(socialResult.currentUser).toEqual({
      driverId: 'driver-1',
      displayName: '',
      avatarUrl: '',
      countryCode: '',
    });

    expect(socialResult.friends).toHaveLength(1);
    expect(socialResult.friends[0]).toEqual({
      driverId: 'friend-1',
      displayName: 'Friend One',
      avatarUrl: '',
      countryCode: '',
      isOnline: false,
      lastSeen: new Date('2025-01-01T00:00:00.000Z'),
    });

    expect(logger.warn).not.toHaveBeenCalled();

    vi.useRealTimers();
  });

  it('returns empty friends list when no friends exist', async () => {
    socialGraphRepository.getFriends.mockResolvedValue([]);

    const input: GetCurrentUserSocialInput = { driverId: 'driver-1' };
    const result = await useCase.execute(input);

    expect(result.isOk()).toBe(true);
    const socialResult = result.unwrap();

    expect(socialResult.friends).toEqual([]);
    expect(socialResult.currentUser.driverId).toBe('driver-1');

    expect(logger.warn).toHaveBeenCalledTimes(1);
    expect((logger.warn as Mock).mock.calls[0]![0]).toBe(
      'GetCurrentUserSocialUseCase.execute: No friends found for driverId: driver-1',
    );
  });

  it('returns REPOSITORY_ERROR when repository throws', async () => {
    socialGraphRepository.getFriends.mockRejectedValue(new Error('DB error'));

    const input: GetCurrentUserSocialInput = { driverId: 'driver-1' };
    const result = await useCase.execute(input);

    expect(result.isErr()).toBe(true);

    const err = result.unwrapErr() as GetCurrentUserSocialApplicationError;
    expect(err.code).toBe('REPOSITORY_ERROR');
    expect(err.details.message).toBe('DB error');

    expect(logger.error).toHaveBeenCalledTimes(1);
  });
});