// src/services/nominatimGeocodingService.server.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';

vi.unmock('./nominatimGeocodingService.server');

// Mock the logger to prevent console output and allow for assertions
vi.mock('./logger.server', () => ({
  logger: {
    info: vi.fn(),
    warn: vi.fn(),
    error: vi.fn(),
    debug: vi.fn(),
  },
}));

// Import the function to be tested after setting up mocks
import { nominatimGeocodingService } from './nominatimGeocodingService.server';
import { logger as mockLogger } from './logger.server';

describe('Nominatim Geocoding Service', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Mock the global fetch function before each test
    vi.stubGlobal('fetch', vi.fn());
  });

  it('should return coordinates for a valid address', async () => {
    // Arrange: Mock a successful API response from Nominatim
    const mockApiResponse = [{
      lat: '48.4284',
      lon: '-123.3656',
      display_name: 'Victoria, BC, Canada',
    }];
    vi.mocked(fetch).mockResolvedValue({
      ok: true,
      json: async () => mockApiResponse,
    } as Response);

    // Act
    const result = await nominatimGeocodingService.geocode('Victoria, BC', mockLogger);

    // Assert
    expect(result).toEqual({ lat: 48.4284, lng: -123.3656 });
    expect(mockLogger.info).toHaveBeenCalledWith({ address: 'Victoria, BC', result: { lat: '48.4284', lon: '-123.3656' } }, `[NominatimService] Successfully geocoded address`);
    expect(mockLogger.error).not.toHaveBeenCalled();
  });

  it('should return null if the API returns no results', async () => {
    // Arrange: Mock an empty array response
    vi.mocked(fetch).mockResolvedValue({
      ok: true,
      json: async () => [],
    } as Response);

    // Act
    const result = await nominatimGeocodingService.geocode('NonExistentPlace 12345', mockLogger);

    // Assert
    expect(result).toBeNull();
    expect(mockLogger.warn).toHaveBeenCalledWith({ address: 'NonExistentPlace 12345' }, '[NominatimService] Geocoding failed or returned no results.');
    expect(mockLogger.error).not.toHaveBeenCalled();
  });

  it('should return null and log an error if the fetch call fails', async () => {
    // Arrange: Mock the fetch call to reject with an error
    const networkError = new Error('Network request failed');
    vi.mocked(fetch).mockRejectedValue(networkError);

    // Act
    const result = await nominatimGeocodingService.geocode('Any Address', mockLogger);

    // Assert
    expect(result).toBeNull();
    expect(mockLogger.error).toHaveBeenCalledWith({ err: networkError, address: 'Any Address' }, '[NominatimService] An error occurred while calling the Nominatim API.');
  });
});