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('paymentDetailsAddEdit thunk', () => {
    const mockDispatch = jest.fn();
    const mockCallback = jest.fn();

    /**
     * Asynchronous thunk action for adding or editing payment details for a booking.
     * @param payload - The data required for adding or editing payment details.
     * @param callback - Optional callback function that receives API response data.
     * @returns A thunk function that dispatches actions based on API response.
     */
    const paymentDetailsAddEdit =
        (payload: any, callback?: (data: any) => void) =>
            async (dispatch: any) => {
                try {
                    dispatch({ type: 'REQUEST_PAYMENT_DETAILS_ADD_EDIT' });

                    const response: any = await apiClient.post(API_ENDPOINTS.PAYMENT_DETAILS_ADD_EDIT, payload);

                    if (response?.data?.meta?.status === 0) {
                        // Skipping Toast
                    } else {
                        callback && callback(response?.data);
                    }

                    dispatch({ type: 'SUCCESS_PAYMENT_DETAILS_ADD_EDIT', payload: response?.data });
                } catch (error: any) {
                    dispatch({ type: 'FAILURE_PAYMENT_DETAILS_ADD_EDIT' });
                    // Skipping Toast
                }
            };

    const payload = {
        paymentDetailId: 'pd-001',
        name: 'John Doe',
        paymentDetailType: 'card',
        cardType: 'mastercard',
        cardNumber: '5555555555554444',
        cardExpiry: '12/27',
        cardCvv: '123',
        saveForFutureUsage: true,
    };

    const mockSuccessResponse = {
        data: {
            meta: {
                status: 1,
                message: 'Payment method saved',
            },
            data: {
                paymentDetailId: 'pd-001',
                name: 'John Doe',
            },
        },
    };

    const mockHandledErrorResponse = {
        data: {
            meta: {
                status: 0,
                message: 'Card number is invalid',
            },
        },
    };

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

    it('should dispatch success and call callback when meta.status is 1', async () => {
        mockedApi.post.mockResolvedValueOnce(mockSuccessResponse);

        await paymentDetailsAddEdit(payload, mockCallback)(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({ type: 'REQUEST_PAYMENT_DETAILS_ADD_EDIT' });
        expect(mockedApi.post).toHaveBeenCalledWith(API_ENDPOINTS.PAYMENT_DETAILS_ADD_EDIT, payload);
        expect(mockCallback).toHaveBeenCalledWith(mockSuccessResponse.data);
        expect(mockDispatch).toHaveBeenCalledWith({
            type: 'SUCCESS_PAYMENT_DETAILS_ADD_EDIT',
            payload: mockSuccessResponse.data,
        });
    });

    it('should dispatch success but not call callback when meta.status is 0', async () => {
        mockedApi.post.mockResolvedValueOnce(mockHandledErrorResponse);

        await paymentDetailsAddEdit(payload, mockCallback)(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({ type: 'REQUEST_PAYMENT_DETAILS_ADD_EDIT' });
        expect(mockCallback).not.toHaveBeenCalled();
        expect(mockDispatch).toHaveBeenCalledWith({
            type: 'SUCCESS_PAYMENT_DETAILS_ADD_EDIT',
            payload: mockHandledErrorResponse.data,
        });
    });

    it('should dispatch failure when API call throws error', async () => {
        mockedApi.post.mockRejectedValueOnce(new Error('Network error'));

        await paymentDetailsAddEdit(payload, mockCallback)(mockDispatch);

        expect(mockDispatch).toHaveBeenCalledWith({ type: 'REQUEST_PAYMENT_DETAILS_ADD_EDIT' });
        expect(mockDispatch).toHaveBeenCalledWith({ type: 'FAILURE_PAYMENT_DETAILS_ADD_EDIT' });
        expect(mockCallback).not.toHaveBeenCalled();
    });
});
