/**
 * Integration Test: GetDriverUseCase Orchestration
 * 
 * Tests the orchestration logic of GetDriverUseCase:
 * - GetDriverUseCase: Retrieves a single driver by ID
 * - Validates that Use Cases correctly interact with their Ports (Repositories)
 * - Uses In-Memory adapters for fast, deterministic testing
 * 
 * Focus: Business logic orchestration, NOT UI rendering
 */

import { describe, it, expect, beforeAll, beforeEach } from 'vitest';
import { InMemoryDriverRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverRepository';
import { GetDriverUseCase } from '../../../core/racing/application/use-cases/GetDriverUseCase';
import { Driver } from '../../../core/racing/domain/entities/Driver';
import { MediaReference } from '../../../core/domain/media/MediaReference';
import { Logger } from '../../../core/shared/domain/Logger';

describe('GetDriverUseCase Orchestration', () => {
  let driverRepository: InMemoryDriverRepository;
  let getDriverUseCase: GetDriverUseCase;
  let mockLogger: Logger;

  beforeAll(() => {
    mockLogger = {
      info: () => {},
      debug: () => {},
      warn: () => {},
      error: () => {},
    } as unknown as Logger;
    
    driverRepository = new InMemoryDriverRepository(mockLogger);
    getDriverUseCase = new GetDriverUseCase(driverRepository);
  });

  beforeEach(() => {
    // Clear all In-Memory repositories before each test
    driverRepository.clear();
  });

  describe('GetDriverUseCase - Success Path', () => {
    it('should retrieve complete driver with all data', async () => {
      // Scenario: Driver with complete profile data
      // Given: A driver exists with personal information (name, avatar, bio, country)
      const driverId = 'driver-123';
      const driver = Driver.create({
        id: driverId,
        iracingId: '12345',
        name: 'John Doe',
        country: 'US',
        bio: 'A passionate racer with 10 years of experience',
        avatarRef: MediaReference.createUploaded('avatar-123'),
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain all driver data
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.iracingId.toString()).toBe('12345');
      expect(retrievedDriver.name.toString()).toBe('John Doe');
      expect(retrievedDriver.country.toString()).toBe('US');
      expect(retrievedDriver.bio?.toString()).toBe('A passionate racer with 10 years of experience');
      expect(retrievedDriver.avatarRef).toBeDefined();
    });

    it('should retrieve driver with minimal data', async () => {
      // Scenario: Driver with minimal profile data
      // Given: A driver exists with only basic information (name, country)
      const driverId = 'driver-456';
      const driver = Driver.create({
        id: driverId,
        iracingId: '67890',
        name: 'Jane Smith',
        country: 'UK',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain basic driver info
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.iracingId.toString()).toBe('67890');
      expect(retrievedDriver.name.toString()).toBe('Jane Smith');
      expect(retrievedDriver.country.toString()).toBe('UK');
      expect(retrievedDriver.bio).toBeUndefined();
      expect(retrievedDriver.avatarRef).toBeDefined();
    });

    it('should retrieve driver with bio but no avatar', async () => {
      // Scenario: Driver with bio but no avatar
      // Given: A driver exists with bio but no avatar
      const driverId = 'driver-789';
      const driver = Driver.create({
        id: driverId,
        iracingId: '11111',
        name: 'Bob Johnson',
        country: 'CA',
        bio: 'Canadian racer',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain driver info with bio
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.bio?.toString()).toBe('Canadian racer');
      expect(retrievedDriver.avatarRef).toBeDefined();
    });

    it('should retrieve driver with avatar but no bio', async () => {
      // Scenario: Driver with avatar but no bio
      // Given: A driver exists with avatar but no bio
      const driverId = 'driver-999';
      const driver = Driver.create({
        id: driverId,
        iracingId: '22222',
        name: 'Alice Brown',
        country: 'DE',
        avatarRef: MediaReference.createUploaded('avatar-999'),
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain driver info with avatar
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.bio).toBeUndefined();
      expect(retrievedDriver.avatarRef).toBeDefined();
    });
  });

  describe('GetDriverUseCase - Edge Cases', () => {
    it('should handle driver with no bio', async () => {
      // Scenario: Driver with no bio
      // Given: A driver exists
      const driverId = 'driver-no-bio';
      const driver = Driver.create({
        id: driverId,
        iracingId: '33333',
        name: 'No Bio Driver',
        country: 'FR',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain driver profile
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.bio).toBeUndefined();
    });

    it('should handle driver with no avatar', async () => {
      // Scenario: Driver with no avatar
      // Given: A driver exists
      const driverId = 'driver-no-avatar';
      const driver = Driver.create({
        id: driverId,
        iracingId: '44444',
        name: 'No Avatar Driver',
        country: 'ES',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain driver profile
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.avatarRef).toBeDefined();
    });

    it('should handle driver with no data at all', async () => {
      // Scenario: Driver with absolutely no data
      // Given: A driver exists with only required fields
      const driverId = 'driver-minimal';
      const driver = Driver.create({
        id: driverId,
        iracingId: '55555',
        name: 'Minimal Driver',
        country: 'IT',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called with driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should contain basic driver info
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver).toBeDefined();
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.iracingId.toString()).toBe('55555');
      expect(retrievedDriver.name.toString()).toBe('Minimal Driver');
      expect(retrievedDriver.country.toString()).toBe('IT');
      expect(retrievedDriver.bio).toBeUndefined();
      expect(retrievedDriver.avatarRef).toBeDefined();
    });
  });

  describe('GetDriverUseCase - Error Handling', () => {
    it('should return null when driver does not exist', async () => {
      // Scenario: Non-existent driver
      // Given: No driver exists with the given ID
      const driverId = 'non-existent-driver';

      // When: GetDriverUseCase.execute() is called with non-existent driver ID
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The result should be null
      expect(result.isOk()).toBe(true);
      expect(result.unwrap()).toBeNull();
    });

    it('should handle repository errors gracefully', async () => {
      // Scenario: Repository throws error
      // Given: A driver exists
      const driverId = 'driver-error';
      const driver = Driver.create({
        id: driverId,
        iracingId: '66666',
        name: 'Error Driver',
        country: 'US',
      });
      
      await driverRepository.create(driver);

      // Mock the repository to throw an error
      const originalFindById = driverRepository.findById.bind(driverRepository);
      driverRepository.findById = async () => {
        throw new Error('Repository error');
      };

      // When: GetDriverUseCase.execute() is called
      const result = await getDriverUseCase.execute({ driverId });

      // Then: Should propagate the error appropriately
      expect(result.isErr()).toBe(true);
      const error = result.unwrapErr();
      expect(error.message).toBe('Repository error');

      // Restore original method
      driverRepository.findById = originalFindById;
    });
  });

  describe('GetDriverUseCase - Data Orchestration', () => {
    it('should correctly retrieve driver with all fields populated', async () => {
      // Scenario: Driver with all fields populated
      // Given: A driver exists with all possible fields
      const driverId = 'driver-complete';
      const driver = Driver.create({
        id: driverId,
        iracingId: '77777',
        name: 'Complete Driver',
        country: 'US',
        bio: 'Complete driver profile with all fields',
        avatarRef: MediaReference.createUploaded('avatar-complete'),
        category: 'pro',
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called
      const result = await getDriverUseCase.execute({ driverId });

      // Then: All fields should be correctly retrieved
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver.id).toBe(driverId);
      expect(retrievedDriver.iracingId.toString()).toBe('77777');
      expect(retrievedDriver.name.toString()).toBe('Complete Driver');
      expect(retrievedDriver.country.toString()).toBe('US');
      expect(retrievedDriver.bio?.toString()).toBe('Complete driver profile with all fields');
      expect(retrievedDriver.avatarRef).toBeDefined();
      expect(retrievedDriver.category).toBe('pro');
    });

    it('should correctly retrieve driver with system-default avatar', async () => {
      // Scenario: Driver with system-default avatar
      // Given: A driver exists with system-default avatar
      const driverId = 'driver-system-avatar';
      const driver = Driver.create({
        id: driverId,
        iracingId: '88888',
        name: 'System Avatar Driver',
        country: 'US',
        avatarRef: MediaReference.createSystemDefault('avatar'),
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The avatar reference should be correctly retrieved
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver.avatarRef).toBeDefined();
      expect(retrievedDriver.avatarRef.type).toBe('system_default');
    });

    it('should correctly retrieve driver with generated avatar', async () => {
      // Scenario: Driver with generated avatar
      // Given: A driver exists with generated avatar
      const driverId = 'driver-generated-avatar';
      const driver = Driver.create({
        id: driverId,
        iracingId: '99999',
        name: 'Generated Avatar Driver',
        country: 'US',
        avatarRef: MediaReference.createGenerated('gen-123'),
      });
      
      await driverRepository.create(driver);

      // When: GetDriverUseCase.execute() is called
      const result = await getDriverUseCase.execute({ driverId });

      // Then: The avatar reference should be correctly retrieved
      expect(result.isOk()).toBe(true);
      const retrievedDriver = result.unwrap();
      
      expect(retrievedDriver.avatarRef).toBeDefined();
      expect(retrievedDriver.avatarRef.type).toBe('generated');
    });
  });
});
