import { describe, it, expect, vi, Mocked } from 'vitest';
import { AvatarService } from './AvatarService';
import { MediaApiClient } from '@/lib/api/media/MediaApiClient';
import { RequestAvatarGenerationViewModel } from '@/lib/view-models/RequestAvatarGenerationViewModel';
import { AvatarViewModel } from '@/lib/view-models/AvatarViewModel';
import { UpdateAvatarViewModel } from '@/lib/view-models/UpdateAvatarViewModel';

describe('AvatarService', () => {
  let mockApiClient: Mocked<MediaApiClient>;
  let service: AvatarService;

  beforeEach(() => {
    mockApiClient = {
      requestAvatarGeneration: vi.fn(),
      getAvatar: vi.fn(),
      updateAvatar: vi.fn(),
    } as Mocked<MediaApiClient>;

    service = new AvatarService(mockApiClient);
  });

  describe('requestAvatarGeneration', () => {
    it('should call apiClient.requestAvatarGeneration with correct input and return view model', async () => {
      const input = {
        userId: 'user-123',
        facePhotoData: 'base64data',
        suitColor: 'red' as const,
      };

      const expectedOutput = { success: true, avatarUrl: 'https://example.com/avatar.jpg' };
      mockApiClient.requestAvatarGeneration.mockResolvedValue(expectedOutput);

      const result = await service.requestAvatarGeneration(input);

      expect(mockApiClient.requestAvatarGeneration).toHaveBeenCalledWith(input);
      expect(result).toBeInstanceOf(RequestAvatarGenerationViewModel);
      expect(result.success).toBe(true);
      expect(result.avatarUrl).toBe('https://example.com/avatar.jpg');
    });

    it('should handle error response', async () => {
      const input = {
        userId: 'user-123',
        facePhotoData: 'base64data',
        suitColor: 'blue' as const,
      };

      const expectedOutput = { success: false, error: 'Generation failed' };
      mockApiClient.requestAvatarGeneration.mockResolvedValue(expectedOutput);

      const result = await service.requestAvatarGeneration(input);

      expect(result).toBeInstanceOf(RequestAvatarGenerationViewModel);
      expect(result.success).toBe(false);
      expect(result.error).toBe('Generation failed');
    });
  });

  describe('getAvatar', () => {
    it('should call apiClient.getAvatar with driverId and return view model', async () => {
      const driverId = 'driver-123';

      const expectedOutput = { driverId: 'driver-123', avatarUrl: 'https://example.com/avatar.jpg' };
      mockApiClient.getAvatar.mockResolvedValue(expectedOutput);

      const result = await service.getAvatar(driverId);

      expect(mockApiClient.getAvatar).toHaveBeenCalledWith(driverId);
      expect(result).toBeInstanceOf(AvatarViewModel);
      expect(result.driverId).toBe('driver-123');
      expect(result.avatarUrl).toBe('https://example.com/avatar.jpg');
      expect(result.hasAvatar).toBe(true);
    });

    it('should handle driver without avatar', async () => {
      const driverId = 'driver-456';

      const expectedOutput = { driverId: 'driver-456' };
      mockApiClient.getAvatar.mockResolvedValue(expectedOutput);

      const result = await service.getAvatar(driverId);

      expect(result).toBeInstanceOf(AvatarViewModel);
      expect(result.driverId).toBe('driver-456');
      expect(result.avatarUrl).toBeUndefined();
      expect(result.hasAvatar).toBe(false);
    });
  });

  describe('updateAvatar', () => {
    it('should call apiClient.updateAvatar with correct input and return view model', async () => {
      const input = { driverId: 'driver-123', avatarUrl: 'https://example.com/new-avatar.jpg' };

      const expectedOutput = { success: true };
      mockApiClient.updateAvatar.mockResolvedValue(expectedOutput);

      const result = await service.updateAvatar(input);

      expect(mockApiClient.updateAvatar).toHaveBeenCalledWith(input);
      expect(result).toBeInstanceOf(UpdateAvatarViewModel);
      expect(result.success).toBe(true);
      expect(result.isSuccessful).toBe(true);
      expect(result.hasError).toBe(false);
    });

    it('should handle error response', async () => {
      const input = { driverId: 'driver-123', avatarUrl: 'https://example.com/new-avatar.jpg' };

      const expectedOutput = { success: false, error: 'Update failed' };
      mockApiClient.updateAvatar.mockResolvedValue(expectedOutput);

      const result = await service.updateAvatar(input);

      expect(result).toBeInstanceOf(UpdateAvatarViewModel);
      expect(result.success).toBe(false);
      expect(result.error).toBe('Update failed');
      expect(result.isSuccessful).toBe(false);
      expect(result.hasError).toBe(true);
    });
  });
});