import { createMockRepository, createMockCountry } from '../helpers';
import { NotFoundError } from '../../shared/errors';

// Mock the entire module
const mockRepository = createMockRepository();

jest.mock('../../config/typeorm', () => ({
  AppDataSource: {
    getRepository: jest.fn(() => mockRepository),
  },
}));

// Import after mocking
import { countriesService } from '../../modules/core/countries.service';

describe('CountriesService', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('findAll', () => {
    it('should return all countries ordered by name', async () => {
      const mockCountries = [
        createMockCountry({ id: '1', code: 'US', name: 'Estados Unidos' }),
        createMockCountry({ id: '2', code: 'MX', name: 'México' }),
      ];

      mockRepository.find.mockResolvedValue(mockCountries);

      const result = await countriesService.findAll();

      expect(mockRepository.find).toHaveBeenCalledWith({
        order: { name: 'ASC' },
      });
      expect(result).toEqual(mockCountries);
      expect(result).toHaveLength(2);
    });

    it('should return empty array when no countries exist', async () => {
      mockRepository.find.mockResolvedValue([]);

      const result = await countriesService.findAll();

      expect(result).toEqual([]);
      expect(result).toHaveLength(0);
    });
  });

  describe('findById', () => {
    it('should return a country by id', async () => {
      const mockCountry = createMockCountry({ id: 'country-id-1' });
      mockRepository.findOne.mockResolvedValue(mockCountry);

      const result = await countriesService.findById('country-id-1');

      expect(mockRepository.findOne).toHaveBeenCalledWith({
        where: { id: 'country-id-1' },
      });
      expect(result).toEqual(mockCountry);
    });

    it('should throw NotFoundError when country not found', async () => {
      mockRepository.findOne.mockResolvedValue(null);

      await expect(countriesService.findById('non-existent-id')).rejects.toThrow(NotFoundError);
    });
  });

  describe('findByCode', () => {
    it('should return a country by code', async () => {
      const mockCountry = createMockCountry({ code: 'MX' });
      mockRepository.findOne.mockResolvedValue(mockCountry);

      const result = await countriesService.findByCode('MX');

      expect(mockRepository.findOne).toHaveBeenCalledWith({
        where: { code: 'MX' },
      });
      expect(result).toEqual(mockCountry);
    });

    it('should return a country by lowercase code (converted to uppercase)', async () => {
      const mockCountry = createMockCountry({ code: 'MX' });
      mockRepository.findOne.mockResolvedValue(mockCountry);

      const result = await countriesService.findByCode('mx');

      expect(mockRepository.findOne).toHaveBeenCalledWith({
        where: { code: 'MX' },
      });
      expect(result).toEqual(mockCountry);
    });

    it('should return null when country code not found', async () => {
      mockRepository.findOne.mockResolvedValue(null);

      const result = await countriesService.findByCode('XX');

      expect(result).toBeNull();
    });
  });
});
