/**
 * File: bookingThunks.ts
 * Purpose: This file contains asynchronous thunk actions for managing booking-related workflows 
 *          such as booking list, and more.
 *          
 * Description:
 * - Utilizes `redux-thunk` to create async actions that handle API requests and responses.
 * - Handles booking API calls by dispatching appropriate Redux actions based on the API response.
 * - Displays error notifications using the `Toast` component in case of API failures.
*/

import apiClient from "@/src/interceptor/apiClient";
import { API_ENDPOINTS } from "@/src/utils/commonVariables";
import { bookingActions } from "@/redux/slices/Booking/booking";
import { CancelBookingPayload, CreateBookingPayload, ViewBookingPayload } from "@/redux/types/bookingType";
import { Toast } from "@/src/components/Toast";

/**
 * Asynchronous thunk action for View Property Availability process.
 * @param payload - The data required for booking View Property Availability.
 * @param callback - Optional callback function that receives API response data.
 * @returns A thunk function that dispatches actions based on API response.
 */
export const getViewPropertyAvailability =
    (payload: { propertyId: string, bookingId?: string, propertySpaceIds?: string[] }, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestViewPropertyAvailability());
                const response: any = await apiClient.post(API_ENDPOINTS.BOOKING_VIEW_PROPERTY_AVAILABILITY, payload);
                callback && callback(response?.data);
                dispatch(bookingActions.successViewPropertyAvailability(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureViewPropertyAvailability());
            }
        };

export default getViewPropertyAvailability;

/**
 * Asynchronous thunk action for View Booking Summary process.
 * @param payload - The data required for booking View Booking Summary.
 * @param callback - Optional callback function that receives API response data.
 * @returns A thunk function that dispatches actions based on API response.
 */
const inProgressRequests = new Set<string>();
let lastPayload = null
let lastPayloadTimeout: any = null

export const getBookingSummary =
    (
        payload: {
            propertyId: string;
            checkInDate: string;
            checkOutDate: string;
            numberOfGuest: number;
        },
        callback?: (data: any) => void
    ) =>
        async (dispatch: any) => {
            // Serialize payload to a unique key
            const requestKey = JSON.stringify(payload);
            // Prevent duplicate request
            if (inProgressRequests.has(requestKey)) return;

            if (
                lastPayload?.checkInDate === payload?.checkInDate &&
                lastPayload?.checkOutDate === payload?.checkOutDate &&
                lastPayload?.propertyId === payload?.propertyId &&
                lastPayload?.numberOfGuest === payload?.numberOfGuest
            ) {
                return
            }

            if (payload?.checkInDate === payload?.checkOutDate) return;

            try {
                lastPayload = payload
                if (lastPayloadTimeout) clearTimeout(lastPayloadTimeout);
                lastPayloadTimeout = setTimeout(() => {
                    lastPayload = null;
                }, 5000);

                inProgressRequests.add(requestKey);

                dispatch(bookingActions.requestBookingSummary());
                const response: any = await apiClient.post(API_ENDPOINTS.BOOKING_SUMMARY, payload);

                callback && callback(response?.data);
                dispatch(bookingActions.successBookingSummary(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureBookingSummary());
            } finally {
                inProgressRequests.delete(requestKey); // Clean up
            }
        };


/**
 * Asynchronous thunk action for create booking process.
 * @param payload - The data required for creating a booking.
 * @param callback - Optional callback function that receives API response data.
 * @returns A thunk function that dispatches actions based on API response.
 */

export const createBooking =
    (payload: CreateBookingPayload, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestCreateBooking());
                const response: any = await apiClient.post(API_ENDPOINTS.CREATE_BOOKING, payload);
                if (response?.data?.meta?.status === 0) {
                    Toast('error', response?.data?.meta?.message);
                } else {
                    callback && callback(response?.data);
                }
                dispatch(bookingActions.successCreateBooking(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureCreateBooking());
                Toast('error', error?.response?.data?.message);
            }
        };


/**
 * Asynchronous thunk action for View Booking process.
 * @param payload - The data required for viewing a booking.
 * @param callback - Optional callback function that receives API response data.
 * @returns A thunk function that dispatches actions based on API response.
 */
export const getViewBooking =
    (payload: ViewBookingPayload, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestViewBooking());
                const response: any = await apiClient.post(API_ENDPOINTS.VIEW_BOOKING, payload);
                callback && callback(response?.data);
                dispatch(bookingActions.successViewBooking(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureViewBooking());
                Toast('error', error?.response?.data?.message);
            }
        };

/**
 * Asynchronous thunk action for getting payment details list for a booking.
 * @param payload - The data required for getting payment details list.
 * @param callback - Optional callback function that receives API response data.
 * @returns A thunk function that dispatches actions based on API response.
 */
export const getPaymentDetailsList =
    (payload: { page: number, perPage: number }, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestPaymentDetailsList());
                const response: any = await apiClient.post(API_ENDPOINTS.PAYMENT_DETAILS_LIST, payload);
                if (response?.data?.meta?.status === 0) {
                    Toast('error', response?.data?.meta?.message);
                } else {
                    callback && callback(response?.data);
                }
                dispatch(bookingActions.successPaymentDetailsList(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failurePaymentDetailsList());
                Toast('error', error?.response?.data?.message);
            }
        };

/**
 * 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.
 */
export const paymentDetailsAddEdit =
    (payload: any, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestPaymentDetailsAddEdit());
                const response: any = await apiClient.post(API_ENDPOINTS.PAYMENT_DETAILS_ADD_EDIT, payload);
                if (response?.data?.meta?.status === 0) {
                    Toast('error', response?.data?.meta?.message);
                } else {
                    callback && callback(response?.data);
                }
                dispatch(bookingActions.successPaymentDetailsAddEdit(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failurePaymentDetailsAddEdit());
                Toast('error', error?.response?.data?.message);
            }
        };

/**
 * Asynchronous thunk action for the cancel booking process.
 * Dispatches actions representing the various states of the API call: request, success, or failure.
 * 
 * @param payload - The data required to cancel a booking.
 * @param callback - Optional callback function that receives the API response data if the call is successful.
 * 
 * Dispatches:
 * - REQUEST_CANCEL_BOOKING: Before the API call to indicate loading.
 * - SUCCESS_CANCEL_BOOKING: On successful API response with the cancellation data.
 * - FAILURE_CANCEL_BOOKING: In case of an API error.
 * 
 * Displays a toast notification on success or error based on the API response.
 */
export const cancelBooking =
    (payload: CancelBookingPayload, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestCancelBooking());
                const response: any = await apiClient.post(API_ENDPOINTS.CANCEL_BOOKING, payload);
                if (response?.data?.meta?.status === 0) {
                    Toast('error', response?.data?.meta?.message);
                }
                callback && callback(response?.data);
                dispatch(bookingActions.successCancelBooking(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureCancelBooking());
                Toast('error', error?.response?.data?.message);
            }
        };       


/**
 * Asynchronous thunk action for raising a dispute on a booking.
 * Dispatches actions representing the various states of the API call: request, success, or failure.
 * 
 * @param payload - The data required to raise a dispute on a booking.
 * @param callback - Optional callback function that receives the API response data if the call is successful.
 * 
 * Dispatches:
 * - REQUEST_RAISE_DISPUTE: Before the API call to indicate loading.
 * - SUCCESS_RAISE_DISPUTE: On successful API response with the dispute data.
 * - FAILURE_RAISE_DISPUTE: In case of an API error.
 * 
 * Displays a toast notification on success or error based on the API response.
 */
export const raiseDispute =
    (payload: any, callback?: (data: any) => void) =>
        async (dispatch: any) => {
            try {
                dispatch(bookingActions.requestRaiseDispute());
                const response: any = await apiClient.post(API_ENDPOINTS.RAISE_DISPUTE, payload);
                if (response?.data?.meta?.status === 0) {
                    Toast('error', response?.data?.meta?.message);
                }
                callback && callback(response?.data);
                dispatch(bookingActions.successRaiseDispute(response?.data));
            } catch (error: any) {
                dispatch(bookingActions.failureRaiseDispute());
                Toast('error', error?.response?.data?.message);
            }
        };       
