/**
 * @ai-summary Tests for useStationsSearch hook
 */

import React from 'react';
import { renderHook, waitFor } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useStationsSearch } from '../../hooks/useStationsSearch';
import { stationsApi } from '../../api/stations.api';
import { Station } from '../../types/stations.types';

jest.mock('../../api/stations.api');

const mockStations: Station[] = [
  {
    placeId: 'test-1',
    name: 'Shell Station',
    address: '123 Main St',
    latitude: 37.7749,
    longitude: -122.4194,
    rating: 4.2,
    distance: 250
  },
  {
    placeId: 'test-2',
    name: 'Chevron Station',
    address: '456 Market St',
    latitude: 37.7923,
    longitude: -122.3989,
    rating: 4.5,
    distance: 1200
  }
];

const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false }
    }
  });
  return ({ children }: { children: React.ReactNode }): React.ReactElement =>
    React.createElement(
      QueryClientProvider,
      { client: queryClient },
      children
    );
};

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

  describe('Search Execution', () => {
    it('should search for stations and return results', async () => {
      (stationsApi.searchStations as jest.Mock).mockResolvedValue(mockStations);

      const { result } = renderHook(() => useStationsSearch(), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194,
        radius: 5000
      });

      await waitFor(() => {
        expect(result.current.isSuccess).toBe(true);
      });

      expect(result.current.data).toEqual(mockStations);
      expect(stationsApi.searchStations).toHaveBeenCalledWith({
        latitude: 37.7749,
        longitude: -122.4194,
        radius: 5000
      });
    });

    it('should handle search with custom radius', async () => {
      (stationsApi.searchStations as jest.Mock).mockResolvedValue(mockStations);

      const { result } = renderHook(() => useStationsSearch(), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194,
        radius: 10000
      });

      await waitFor(() => {
        expect(result.current.isSuccess).toBe(true);
      });

      expect(stationsApi.searchStations).toHaveBeenCalledWith({
        latitude: 37.7749,
        longitude: -122.4194,
        radius: 10000
      });
    });
  });

  describe('Loading States', () => {
    it('should show pending state during search', () => {
      (stationsApi.searchStations as jest.Mock).mockImplementation(
        () => new Promise((resolve) => setTimeout(() => resolve(mockStations), 100))
      );

      const { result } = renderHook(() => useStationsSearch(), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194
      });

      expect(result.current.isPending).toBe(true);
    });

    it('should clear pending state after success', async () => {
      (stationsApi.searchStations as jest.Mock).mockResolvedValue(mockStations);

      const { result } = renderHook(() => useStationsSearch(), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194
      });

      await waitFor(() => {
        expect(result.current.isPending).toBe(false);
      });
    });
  });

  describe('Error Handling', () => {
    it('should handle API errors', async () => {
      const error = new Error('API Error');
      (stationsApi.searchStations as jest.Mock).mockRejectedValue(error);

      const { result } = renderHook(() => useStationsSearch(), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194
      });

      await waitFor(() => {
        expect(result.current.isError).toBe(true);
      });

      expect(result.current.error).toBeDefined();
    });

    it('should call onError callback on failure', async () => {
      const error = new Error('Network error');
      (stationsApi.searchStations as jest.Mock).mockRejectedValue(error);

      const onError = jest.fn();
      const { result } = renderHook(() => useStationsSearch({ onError }), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194
      });

      await waitFor(() => {
        expect(onError).toHaveBeenCalled();
      });
    });
  });

  describe('Success Callback', () => {
    it('should call onSuccess callback with data', async () => {
      (stationsApi.searchStations as jest.Mock).mockResolvedValue(mockStations);

      const onSuccess = jest.fn();
      const { result } = renderHook(() => useStationsSearch({ onSuccess }), {
        wrapper: createWrapper()
      });

      result.current.mutate({
        latitude: 37.7749,
        longitude: -122.4194
      });

      await waitFor(() => {
        expect(onSuccess).toHaveBeenCalledWith(mockStations);
      });
    });
  });
});
