import { apiUrl, requestWithRefresh } from './http';
import { jsonHeaders } from './config';
import { initToken, refreshToken } from './tokenApi';
import type { CartUpdateResponse, InitialData } from '../types/api';

export async function loadInitialData(): Promise<InitialData> {
    try {
        const response = await fetch(apiUrl('/api/promo/get_initial_data'), {
            credentials: 'include',
        });

        const data = await response.json();

        if (response.status === 400) {
            await clearGuestCookie();
            document.location.reload();
            return fallbackInitialData;
        }

        if (response.status === 401 && data.error_message !== 'need_refresh') {
            await initToken();
            await new Promise(resolve => setTimeout(resolve, 100));

            const retryResponse = await fetch(apiUrl('/api/promo/get_initial_data'), {
                credentials: 'include',
            });

            return retryResponse.json();
        }

        // Handle 403 or need_refresh cases
        if (response.status === 403 || data.error_message === 'need_refresh') {
            await refreshToken();
            const retryResponse = await fetch(apiUrl('/api/promo/get_initial_data'), {
                credentials: 'include',
            });
            return retryResponse.json();
        }

        // Success case
        return data;
    } catch (error) {
        console.error('Error in loadInitialData:', error);
        return fallbackInitialData;
    }
}

export function getCartUpdates(): Promise<CartUpdateResponse> {
    return new Promise<CartUpdateResponse>((resolve, reject) => {
        // Use a simple mutex to ensure only one request is active at a time
        let isPending = false;
        let pendingRequest: Promise<CartUpdateResponse | null> | null = null;

        if (isPending) {
            // If already pending, reject the current request and return a placeholder
            return reject(new Error('getCartUpdates is already in progress'));
        }

        isPending = true;

        // Create a new request that will resolve when the actual request completes
        pendingRequest = requestWithRefresh<CartUpdateResponse>(apiUrl('/api/promo/get_updates'), {
            headers: jsonHeaders,
        }).then(
            (response) => {
                isPending = false;
                resolve(response as CartUpdateResponse);
                return response;
            },
            (error) => {
                isPending = false;
                reject(error);
                return null;
            }
        );

        // Return the promise so the caller can wait for it
        return pendingRequest;
    });
}

export function replaceProduct(productName: string): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/replace_item'), {
        method: 'POST',
        headers: jsonHeaders,
        body: JSON.stringify({ product_name: productName }),
    });
}

export function deleteProduct(productName: string): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/delete_item'), {
        method: 'POST',
        headers: jsonHeaders,
        body: JSON.stringify({ product_name: productName }),
    });
}

export function clearCart(): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/clear_cart'), {
        method: 'POST',
        headers: jsonHeaders,
    });
}

export function setOption<TValue>(key: string, value: TValue): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/set_option'), {
        method: 'POST',
        headers: jsonHeaders,
        body: JSON.stringify({ [key]: value }),
    });
}

export function clearGuestCookie(): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/guest/clear_cookie'), {
        method: 'POST',
    });
}

export function subscribeOnFinish(email: string): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/subscribe'), {
        method: 'POST',
        headers: jsonHeaders,
        body: JSON.stringify({ email }),
    });
}

export function subscribeOnFail(email: string, comment: string): Promise<unknown> {
    return requestWithRefresh(apiUrl('/api/promo/subscribe_fail'), {
        method: 'POST',
        headers: jsonHeaders,
        body: JSON.stringify({ email, comment }),
    });
}

const fallbackInitialData: InitialData = {
    cart: [],
    users: [],
    initial_groups: [],
    available_groups: [],
    fullness: 90,
    days: 7,
    excess: 0,
    precision: 0,
};