const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://api.approagency.ir/api';

interface ApiOptions extends RequestInit {
    token?: string;
}

// Simple in-memory cache for ongoing requests
const pendingRequests = new Map();

class ApiClient {
    private async request<T>(
        endpoint: string,
        options: ApiOptions = {}
    ): Promise<T> {
        const { token, ...fetchOptions } = options;

        const headers: Record<string, string> = {
            ...(options.headers as Record<string, string> || {}),
        };

        // Don't set Content-Type for FormData (browser will set it automatically with boundary)
        if (!(options.body instanceof FormData)) {
            headers['Content-Type'] = 'application/json';
        }

        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }

        // Create a unique key for this request
        const requestKey = `${fetchOptions.method || 'GET'}-${endpoint}-${JSON.stringify(options.body)}`;

        // Check if there's already a pending request with the same key
        if (pendingRequests.has(requestKey)) {
            console.log('Deduplicating request:', endpoint);
            return pendingRequests.get(requestKey);
        }

        // Make the request
        const promise = fetch(`${API_BASE_URL}${endpoint}`, {
            ...fetchOptions,
            headers,
        }).then(async (response) => {
            if (!response.ok) {
                const error = await response.json().catch(() => ({}));
                throw new Error(error.message || 'API request failed');
            }
            return response.json();
        }).finally(() => {
            // Clean up after request completes
            pendingRequests.delete(requestKey);
        });

        // Store the promise
        pendingRequests.set(requestKey, promise);

        return promise;
    }

    async post<T>(endpoint: string, data: any, token?: string): Promise<T> {
        const body = data instanceof FormData ? data : JSON.stringify(data);

        return this.request<T>(endpoint, {
            method: 'POST',
            body,
            token,
        });
    }

    async get<T>(endpoint: string, token?: string): Promise<T> {
        return this.request<T>(endpoint, {
            method: 'GET',
            token,
        });
    }

    async put<T>(endpoint: string, data: any, token?: string): Promise<T> {
        const body = data instanceof FormData ? data : JSON.stringify(data);

        return this.request<T>(endpoint, {
            method: 'PUT',
            body,
            token,
        });
    }

    async patch<T>(endpoint: string, data: any, token?: string): Promise<T> {
        const body = data instanceof FormData ? data : JSON.stringify(data);

        return this.request<T>(endpoint, {
            method: 'PATCH',
            body,
            token,
        });
    }

    async delete<T>(endpoint: string, data?: any, token?: string): Promise<T> {
        const options: ApiOptions = {
            method: 'DELETE',
            token,
        };

        if (data) {
            options.body = data instanceof FormData ? data : JSON.stringify(data);

            if (!(data instanceof FormData)) {
                options.headers = {
                    'Content-Type': 'application/json',
                };
            }
        }

        return this.request<T>(endpoint, options);
    }

    async deleteWithBody<T>(endpoint: string, data: any, token?: string): Promise<T> {
        return this.delete<T>(endpoint, data, token);
    }
}

export const apiClient = new ApiClient();