import { authService } from '~/services/auth.service';

let isRefreshing = false;
let refreshPromise: Promise<string> | null = null;

/**
 * Get token or refresh if needed
 * Handles concurrent requests by sharing same refresh promise
 */
export const getValidToken = async (): Promise<string | null> => {
    const tokenCookie = useCookie('token');
    const refreshTokenCookie = useCookie('refreshToken');

    // If we have token, return it
    if (tokenCookie.value) {
        return tokenCookie.value;
    }

    // No token but have refresh token, try to refresh
    if (refreshTokenCookie.value) {
        // If already refreshing, wait for that promise
        if (isRefreshing && refreshPromise) {
            return refreshPromise;
        }

        try {
            isRefreshing = true;
            const refreshToken = refreshTokenCookie.value;
            refreshPromise = authService.refreshToken(refreshToken).then(res => {
                // Update cookies
                useCookie('token').value = res.token;
                useCookie('refreshToken').value = res.refreshToken;
                return res.token;
            });
            const newToken = await refreshPromise;
            return newToken;
        } catch (error) {
            console.error('Token refresh failed');
            return null;
        } finally {
            isRefreshing = false;
            refreshPromise = null;
        }
    }

    return null;
};

/**
 * Handle 401 error - try to refresh and return new token
 * Returns null if refresh fails
 */
export const handleUnauthorized = async (): Promise<string | null> => {
    const refreshTokenCookie = useCookie('refreshToken');

    if (!refreshTokenCookie.value) {
        return null;
    }

    // If already refreshing, wait for that promise
    if (isRefreshing && refreshPromise) {
        return refreshPromise;
    }

    try {
        isRefreshing = true;
        const refreshToken = refreshTokenCookie.value;
        refreshPromise = authService.refreshToken(refreshToken).then(res => {
            // Update cookies
            useCookie('token').value = res.token;
            useCookie('refreshToken').value = res.refreshToken;
            return res.token;
        });
        const newToken = await refreshPromise;
        console.log('Token refreshed successfully');
        return newToken;
    } catch (error) {
        console.error('Token refresh failed, need to login again');
        // Clear all auth cookies
        useCookie('token').value = null;
        useCookie('refreshToken').value = null;
        useCookie('user').value = null;
        return null;
    } finally {
        isRefreshing = false;
        refreshPromise = null;
    }
};

/**
 * Create authenticated fetch with auto token refresh
 */
export const createAuthFetch = () => {
    const config = useRuntimeConfig();

    return async <T>(
        url: string,
        options: {
            method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
            body?: any;
            headers?: Record<string, string>;
        } = {}
    ): Promise<T> => {
        const token = await getValidToken();

        const makeRequest = async (authToken: string | null) => {
            return await $fetch<T>(url, {
                baseURL: config.public.apiBaseUrl as string,
                method: options.method || 'GET',
                headers: {
                    ...options.headers,
                    ...(authToken ? { Authorization: `Bearer ${authToken}` } : {})
                },
                body: options.body
            });
        };

        try {
            return await makeRequest(token);
        } catch (error: any) {
            // If 401, try to refresh
            if (error.response?.status === 401) {
                const newToken = await handleUnauthorized();
                if (newToken) {
                    // Retry with new token
                    return await makeRequest(newToken);
                }
                // Redirect to login
                navigateTo('/login');
            }
            throw error;
        }
    };
};
