/**
 * @author: Hemal
 * File: getBookingSummary.test.ts
 * Purpose: Unit tests for `getBookingSummary` thunk (defined inline).
 * Description:
 * - Defines thunk inline to test without external imports.
 * - Handles success, duplicate prevention, and failure scenarios.
 */

jest.mock('../../src/interceptor/apiClient');

import apiClient from '../../src/interceptor/apiClient';
import { API_ENDPOINTS } from '@/src/utils/commonVariables';

const mockedApi = apiClient as jest.Mocked<typeof apiClient>;

describe('getBookingSummary thunk', () => {
    const mockDispatch = jest.fn();

    const inProgressRequests = new Set<string>();
    
    /**
     * Asynchronous thunk action for getting booking summary.
     * Dispatches actions based on the API response.
     * 
     * @param payload - The data required for booking summary.
     * @param callback - Optional callback function that receives the API response data.
     * 
     * Dispatches:
     * - REQUEST_BOOKING_SUMMARY: Before the API call to indicate loading.
     * - SUCCESS_BOOKING_SUMMARY: On successful API response with the booking summary data.
     * - FAILURE_BOOKING_SUMMARY: On API error.
     */
    const getBookingSummary =
        (
            payload: {
                propertyId: string;
                checkInDate: string;
                checkOutDate: string;
                numberOfGuest: number;
            },
            callback?: (data: any) => void
        ) =>
            async (dispatch: any) => {
                const requestKey = JSON.stringify(payload);
                if (inProgressRequests.has(requestKey)) return;

                try {
                    inProgressRequests.add(requestKey);

                    dispatch({ type: 'REQUEST_BOOKING_SUMMARY' });
                    const response = await apiClient.post(API_ENDPOINTS.BOOKING_SUMMARY, payload);

                    callback && callback(response?.data);
                    dispatch({
                        type: 'SUCCESS_BOOKING_SUMMARY',
                        payload: response?.data,
                    });
                } catch (error) {
                    dispatch({ type: 'FAILURE_BOOKING_SUMMARY' });
                } finally {
                    inProgressRequests.delete(requestKey);
                }
            };

    const mockPayload = {
        propertyId: 'property123',
        checkInDate: '2025-08-01',
        checkOutDate: '2025-08-05',
        numberOfGuest: 2,
    };

    const mockResponse = {
        statusCode: 200,
        data: {
            totalPrice: 450,
            currency: 'EUR',
            nights: 4,
        },
    };

    beforeEach(() => {
        jest.clearAllMocks();
        inProgressRequests.clear();
    });

    // ✅ Test: Successful API call
    it('should dispatch success actions and call callback on success', async () => {
        const mockCallback = jest.fn();
        mockedApi.post.mockResolvedValueOnce({ data: mockResponse });

        await getBookingSummary(mockPayload, mockCallback)(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({ type: 'REQUEST_BOOKING_SUMMARY' });
        expect(mockedApi.post).toHaveBeenCalledWith(API_ENDPOINTS.BOOKING_SUMMARY, mockPayload);
        expect(mockCallback).toHaveBeenCalledWith(mockResponse);
        expect(mockDispatch).toHaveBeenCalledWith({
            type: 'SUCCESS_BOOKING_SUMMARY',
            payload: mockResponse,
        });
    });

    // ✅ Test: Prevent duplicate requests
    it('should skip API call if request is already in progress', async () => {
        const requestKey = JSON.stringify(mockPayload);
        inProgressRequests.add(requestKey);

        await getBookingSummary(mockPayload)(mockDispatch);

        expect(mockDispatch).not.toHaveBeenCalled();
        expect(mockedApi.post).not.toHaveBeenCalled();
    });

    // ❌ Test: API failure
    it('should dispatch failure action when API call fails', async () => {
        mockedApi.post.mockRejectedValueOnce(new Error('API failed'));

        await getBookingSummary(mockPayload)(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({ type: 'REQUEST_BOOKING_SUMMARY' });
        expect(mockDispatch).toHaveBeenCalledWith({ type: 'FAILURE_BOOKING_SUMMARY' });
    });
});
