import { describe, it, expect, beforeEach, vi, Mock } from 'vitest';
import { GetTeamJoinRequestsUseCase } from './GetTeamJoinRequestsUseCase';
import { ITeamMembershipRepository } from '../../domain/repositories/ITeamMembershipRepository';
import { IDriverRepository } from '../../domain/repositories/IDriverRepository';
import { IImageServicePort } from '../ports/IImageServicePort';
import { Driver } from '../../domain/entities/Driver';
import type { Logger } from '@core/shared/application';

describe('GetTeamJoinRequestsUseCase', () => {
  let useCase: GetTeamJoinRequestsUseCase;
  let membershipRepository: {
    getJoinRequests: Mock;
  };
  let driverRepository: {
    findById: Mock;
  };
  let imageService: {
    getDriverAvatar: Mock;
  };
  let logger: {
    debug: Mock;
    info: Mock;
    warn: Mock;
    error: Mock;
  };

  beforeEach(() => {
    membershipRepository = {
      getJoinRequests: vi.fn(),
    };
    driverRepository = {
      findById: vi.fn(),
    };
    imageService = {
      getDriverAvatar: vi.fn(),
    };
    logger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    };
    useCase = new GetTeamJoinRequestsUseCase(
      membershipRepository as unknown as ITeamMembershipRepository,
      driverRepository as unknown as IDriverRepository,
      imageService as unknown as IImageServicePort,
      logger as unknown as Logger,
    );
  });

  it('should return join requests with driver names and avatar urls', async () => {
    const teamId = 'team-1';
    const joinRequests = [
      { id: 'req-1', teamId, driverId: 'driver-1', requestedAt: new Date(), message: 'msg' },
      { id: 'req-2', teamId, driverId: 'driver-2', requestedAt: new Date() },
    ];
    const driver1 = Driver.create({
      id: 'driver-1',
      iracingId: '123',
      name: 'Driver 1',
      country: 'US',
    });
    const driver2 = Driver.create({
      id: 'driver-2',
      iracingId: '456',
      name: 'Driver 2',
      country: 'UK',
    });

    membershipRepository.getJoinRequests.mockResolvedValue(joinRequests);
    driverRepository.findById.mockImplementation((id: string) => {
      if (id === 'driver-1') return Promise.resolve(driver1);
      if (id === 'driver-2') return Promise.resolve(driver2);
      return Promise.resolve(null);
    });
    imageService.getDriverAvatar.mockImplementation((id: string) => `avatar-${id}`);

    const result = await useCase.execute({ teamId });

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      requests: joinRequests,
      driverNames: {
        'driver-1': 'Driver 1',
        'driver-2': 'Driver 2',
      },
      avatarUrls: {
        'driver-1': 'avatar-driver-1',
        'driver-2': 'avatar-driver-2',
      },
    });
  });

  it('should handle driver not found', async () => {
    const teamId = 'team-1';
    const joinRequests = [
      { id: 'req-1', teamId, driverId: 'driver-1', requestedAt: new Date() },
    ];

    membershipRepository.getJoinRequests.mockResolvedValue(joinRequests);
    driverRepository.findById.mockResolvedValue(null);
    imageService.getDriverAvatar.mockReturnValue('avatar-driver-1');

    const result = await useCase.execute({ teamId });

    expect(result.isOk()).toBe(true);
    expect(result.unwrap()).toEqual({
      requests: joinRequests,
      driverNames: {},
      avatarUrls: {
        'driver-1': 'avatar-driver-1',
      },
    });
  });

  it('should return error on repository failure', async () => {
    const teamId = 'team-1';
    const error = new Error('Repository error');

    membershipRepository.getJoinRequests.mockRejectedValue(error);

    const result = await useCase.execute({ teamId });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr()).toEqual({
      code: 'REPOSITORY_ERROR',
      details: { message: 'Failed to retrieve team join requests' },
    });
  });
});